├── .gitignore ├── Demo ├── App.config ├── App.xaml ├── App.xaml.cs ├── Demo.csproj ├── MainWindow.xaml ├── MainWindow.xaml.cs └── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── README.md ├── TimeLine.sln └── VideoStateAxis ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── Themes └── Generic.xaml ├── VideoStateAxis.csproj └── VideoStateAxisControl.cs /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .vs/ 4 | -------------------------------------------------------------------------------- /Demo/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Demo/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Demo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace Demo 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Demo/Demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DB545297-421D-48C7-B8D1-4344CA7AE080} 8 | WinExe 9 | Demo 10 | Demo 11 | v4.5.2 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | true 17 | 18 | 19 | AnyCPU 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 4.0 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | MSBuild:Compile 56 | Designer 57 | 58 | 59 | MSBuild:Compile 60 | Designer 61 | 62 | 63 | App.xaml 64 | Code 65 | 66 | 67 | MainWindow.xaml 68 | Code 69 | 70 | 71 | 72 | 73 | Code 74 | 75 | 76 | True 77 | True 78 | Resources.resx 79 | 80 | 81 | True 82 | Settings.settings 83 | True 84 | 85 | 86 | ResXFileCodeGenerator 87 | Resources.Designer.cs 88 | 89 | 90 | SettingsSingleFileGenerator 91 | Settings.Designer.cs 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | {c5dc4e69-c26f-4e0d-ba9a-0950a4c15d69} 100 | VideoStateAxis 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Demo/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Demo/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.Windows; 4 | using VideoStateAxis; 5 | 6 | namespace Demo 7 | { 8 | /// 9 | /// Interaction logic for MainWindow.xaml 10 | /// 11 | public partial class MainWindow : Window 12 | { 13 | public MainWindow() 14 | { 15 | InitializeComponent(); 16 | ContentRendered += MainWindow_ContentRendered; 17 | } 18 | 19 | private void MainWindow_ContentRendered(object sender, EventArgs e) 20 | { 21 | var VideoSource = new ObservableCollection(); 22 | 23 | for (int i = 0; i < 10; i++) 24 | { 25 | var item = new VideoStateItem() { CameraName=$"Demo {i.ToString("D2")}",CameraChecked=i%2==0}; 26 | var charList = new char[1000]; 27 | for (int j = 0; j < 1000; j++) 28 | { 29 | charList[j] = '1'; 30 | } 31 | item.AxisHistoryTimeList = charList; 32 | VideoSource.Add(item); 33 | } 34 | 35 | PART_TimeLine.HisVideoSources = VideoSource; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Demo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Demo")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Demo")] 15 | [assembly: AssemblyCopyright("Copyright © 2020")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /Demo/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Demo.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Demo.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Demo/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Demo/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Demo.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Demo/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TimeAxis Control WPF 2 | --- 3 | The WPF-like control of the Adobe AE timeline is completely based on the binding of dependent attributes, which is very extensible and can be modified by itself 4 | 5 | #### View视图代码: 6 | ```C {.line-numbers} 7 | 8 | ``` 9 | 10 | #### 已有依赖属性说明: 11 | >**SerStateTime** 12 | * Type:System.DateTime 13 | * 说明:时间轴开始搜索时间 14 | 15 | >**SerEndTime** 16 | * Type:System.DateTime 17 | * 说明:时间轴结束搜索时间 18 | 19 | >**HistoryVideoSources** 20 | * Type:List\ 21 | * 说明:时间轴时间 22 | * 包含属性: 23 | 24 | ```java {.line-numbers} 25 | public class VideoStateItem 26 | { 27 | /// 28 | /// 相机名称 29 | /// 30 | public string CameraName { get; set; } 31 | 32 | /// 33 | /// 相机是否选中 34 | /// 35 | public bool CameraChecked { get; set; } 36 | 37 | /// 38 | /// 相机历史视频视频时间集 39 | /// 40 | public char[] AxisHistoryTimeList { get; set; } 41 | } 42 | ``` 43 | 44 | ![A](https://github.com/lingme/Picture_Bucket/raw/master/TimeAxis_Control_WPF_img/index_2.jpg) 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /TimeLine.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30011.22 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoStateAxis", "VideoStateAxis\VideoStateAxis.csproj", "{C5DC4E69-C26F-4E0D-BA9A-0950A4C15D69}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "Demo\Demo.csproj", "{DB545297-421D-48C7-B8D1-4344CA7AE080}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C5DC4E69-C26F-4E0D-BA9A-0950A4C15D69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {C5DC4E69-C26F-4E0D-BA9A-0950A4C15D69}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {C5DC4E69-C26F-4E0D-BA9A-0950A4C15D69}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {C5DC4E69-C26F-4E0D-BA9A-0950A4C15D69}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {DB545297-421D-48C7-B8D1-4344CA7AE080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {DB545297-421D-48C7-B8D1-4344CA7AE080}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {DB545297-421D-48C7-B8D1-4344CA7AE080}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {DB545297-421D-48C7-B8D1-4344CA7AE080}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {258197CE-3808-4CEB-AC0F-0EA1755D8F19} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /VideoStateAxis/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("VideoStateAxis")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("VideoStateAxis")] 15 | [assembly: AssemblyCopyright("Copyright © 2017")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | //将 ComVisible 设置为 false 将使此程序集中的类型 20 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请设置 25 | //.csproj 文件中的 CultureYouAreCodingWith 26 | //例如,如果您在源文件中使用的是美国英语, 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly:ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(未在页面中找到资源时使用, 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(未在页面中找到资源时使用, 40 | //、应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 52 | // 方法是按如下所示使用“*”: : 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /VideoStateAxis/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本: 4.0.30319.42000 5 | // 6 | // 对此文件的更改可能导致不正确的行为,如果 7 | // 重新生成代码,则所做更改将丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace VideoStateAxis.Properties { 12 | 13 | 14 | /// 15 | /// 强类型资源类,用于查找本地化字符串等。 16 | /// 17 | // 此类是由 StronglyTypedResourceBuilder 18 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 19 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen 20 | // (以 /str 作为命令选项),或重新生成 VS 项目。 21 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 22 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 23 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 24 | internal class Resources { 25 | 26 | private static global::System.Resources.ResourceManager resourceMan; 27 | 28 | private static global::System.Globalization.CultureInfo resourceCulture; 29 | 30 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 31 | internal Resources() { 32 | } 33 | 34 | /// 35 | /// 返回此类使用的缓存 ResourceManager 实例。 36 | /// 37 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 38 | internal static global::System.Resources.ResourceManager ResourceManager { 39 | get { 40 | if ((resourceMan == null)) { 41 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VideoStateAxis.Properties.Resources", typeof(Resources).Assembly); 42 | resourceMan = temp; 43 | } 44 | return resourceMan; 45 | } 46 | } 47 | 48 | /// 49 | /// 覆盖当前线程的 CurrentUICulture 属性 50 | /// 使用此强类型的资源类的资源查找。 51 | /// 52 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 53 | internal static global::System.Globalization.CultureInfo Culture { 54 | get { 55 | return resourceCulture; 56 | } 57 | set { 58 | resourceCulture = value; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /VideoStateAxis/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /VideoStateAxis/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace VideoStateAxis.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /VideoStateAxis/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /VideoStateAxis/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 53 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 97 | 98 | 99 | 103 | 109 | 113 | 120 | 126 | 127 | 128 | 129 | 130 | 131 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 151 | 159 | 168 | 169 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 224 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 251 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 278 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 321 | 329 | 338 | 339 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 401 | 402 | M955.346899 811.30069 742.294548 406.649604c-11.56643-22.054295-30.487362-22.054295-42.052768 0l-96.1652 182.621271c-11.628852 22.113647-30.487362 22.113647-42.116213 0L394.764414 271.622304c-11.57257-22.110577-30.364565-22.110577-42.059931 0L68.677661 811.30069c-11.622712 22.053272 1.689479 40.008202 29.765931 40.008202l367.720989 0 233.713926 0 225.703485 0C953.655374 851.307869 966.912305 833.352939 955.346899 811.30069M591.184969 320.909847c46.027289 0 83.208097-33.1981 83.208097-74.108858s-37.180807-74.108858-83.208097-74.108858c-45.911656 0-83.148745 33.1981-83.148745 74.108858S545.273313 320.909847 591.184969 320.909847 403 | 404 | 405 | 431 | 432 | 433 | 459 | 460 | 461 | 468 | 469 | 470 | 471 | 472 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 488 | 496 | 502 | 503 | 511 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 540 | 541 | 542 | 543 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 583 | 584 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 608 | 609 | 610 | 611 | 612 | 621 | 622 | 623 | 631 | 632 | 633 | 641 | 642 | 643 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 726 | 736 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 774 | 784 | 796 | 797 | 798 | 799 | 800 | 909 | 910 | 911 | 912 | 913 | 914 | 987 | 988 | 989 | 990 | 991 | 992 | 1004 | 1005 | 1006 | 1007 | 1008 | 1131 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1149 | 1150 | 1151 | 1155 | 1156 | 1160 | 1161 | 1162 | 1163 | 1168 | 1173 | 1174 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1187 | 1193 | 1201 | 1207 | 1215 | 1216 | 1223 | 1224 | 1225 | 1226 | 1231 | 1232 | 1237 | 1243 | 1247 | 1254 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1273 | 1274 | 1275 | 1279 | 1280 | 1284 | 1285 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | -------------------------------------------------------------------------------- /VideoStateAxis/VideoStateAxis.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C5DC4E69-C26F-4E0D-BA9A-0950A4C15D69} 8 | library 9 | VideoStateAxis 10 | VideoStateAxis 11 | v4.5.2 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 4.0 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | MSBuild:Compile 52 | Designer 53 | 54 | 55 | 56 | 57 | Code 58 | 59 | 60 | True 61 | True 62 | Resources.resx 63 | 64 | 65 | True 66 | Settings.settings 67 | True 68 | 69 | 70 | 71 | ResXFileCodeGenerator 72 | Resources.Designer.cs 73 | 74 | 75 | SettingsSingleFileGenerator 76 | Settings.Designer.cs 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /VideoStateAxis/VideoStateAxisControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.ComponentModel; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Text.RegularExpressions; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using System.Windows.Controls; 12 | using System.Windows.Controls.Primitives; 13 | using System.Windows.Data; 14 | using System.Windows.Documents; 15 | using System.Windows.Input; 16 | using System.Windows.Media; 17 | using System.Windows.Media.Imaging; 18 | using System.Windows.Navigation; 19 | using System.Windows.Shapes; 20 | 21 | namespace VideoStateAxis 22 | { 23 | #region TemplatePart 模板元素声明 24 | 25 | [TemplatePart(Name = Parid_axisCanvas)] 26 | [TemplatePart(Name = Parid_timePoint)] 27 | [TemplatePart(Name = Parid_currentTime)] 28 | [TemplatePart(Name = Parid_timePanel)] 29 | [TemplatePart(Name = Parid_timeLine)] 30 | [TemplatePart(Name = Parid_scrollViewer)] 31 | [TemplatePart(Name = Parid_videoHistoryPanel)] 32 | [TemplatePart(Name = Parid__axisCanvasTimeText)] 33 | [TemplatePart(Name = Parid_zoomSlider)] 34 | [TemplatePart(Name = Parid_clipCanvas)] 35 | [TemplatePart(Name = Parid_clipStartBorder)] 36 | [TemplatePart(Name = Parid_clipAreaBorder)] 37 | [TemplatePart(Name = Parid_clipEndBorder)] 38 | [TemplatePart(Name = Parid_clipStackPanel)] 39 | [TemplatePart(Name = Parid_clipOff)] 40 | [TemplatePart(Name = Parid_clipStateTimeTextBlock)] 41 | [TemplatePart(Name = Parid_clipEndTimeTextBlock)] 42 | [TemplatePart(Name = Parid_cameraListBox)] 43 | [TemplatePart(Name = Parid_downButtonListBox)] 44 | 45 | #endregion 46 | public class VideoStateAxisControl : Control 47 | { 48 | #region UIElement 模板元素 49 | 50 | private StackPanel _videoHistoryPanel; //历史时间轴容器 51 | private ScrollViewer _scrollViewer; //滚动视图 52 | private Canvas _axisCanvas; //时间刻度尺容器 53 | private Canvas _axisCanvasTimeText; //时间刻度时间文字容器 54 | private Slider _zoomSlider; //缩放时间轴滑块 55 | 56 | private TextBlock _currentTime; //进度指针时间 57 | private Canvas _timePanel; //进度容器 58 | private Canvas _timeLine; //进度指针容器 59 | private Grid _timePoint; //进度指针 60 | 61 | private Canvas _clipCanvas; //剪辑控制移动容器 62 | private Border _clipStartBorder; //剪辑左调解 63 | private Border _clipAreaBorder; //剪辑滑块 64 | private Border _clipEndBorder; //剪辑右调解 65 | private StackPanel _clipStackPanel; //剪辑滑块容器 66 | private CheckBox _clipOff; //是否开启剪辑控制 67 | 68 | private TextBlock _clipStateTimeTextBlock; //剪辑开始时间指示器 69 | private TextBlock _clipEndTimeTextBlock; //剪辑结束时间指示器 70 | 71 | private ListBox _cameraListBox; //相机列表 72 | private ListBox _downButtonListBox; //下载列表 73 | private ScrollViewer _cameraScrollViewer; //相机列表ScrollViewer 74 | private ScrollViewer _downScrollViewer; //下载列表ScrollViewer 75 | 76 | #endregion 77 | 78 | #region ConstString 模板元素名称,Geometry图像数据 79 | 80 | private const string Parid_axisCanvas = "Z_Parid_axisCanvas"; 81 | private const string Parid__axisCanvasTimeText = "Z_Parid__axisCanvasTimeText"; 82 | private const string Parid_zoomPanel = "Z_Parid_zoomPanel"; 83 | private const string Parid_timePoint = "Z_Parid_timePoint"; 84 | private const string Parid_currentTime = "Z_Parid_currentTime"; 85 | private const string Parid_timePanel = "Z_Parid_timePanel"; 86 | private const string Parid_timeLine = "Z_Parid_timeLine"; 87 | private const string Parid_scrollViewer = "Z_Parid_scrollViewer"; 88 | private const string Parid_videoHistoryPanel = "Z_videoHistoryPanel"; 89 | private const string Parid_zoomSlider = "Z_Parid_zoomSlider"; 90 | private const string Parid_clipCanvas = "Z_Parid_clipCanvas"; 91 | private const string Parid_clipStartBorder = "Z_Parid_clipStartBorder"; 92 | private const string Parid_clipAreaBorder = "Z_Parid_clipAreaBorder"; 93 | private const string Parid_clipEndBorder = "Z_Parid_clipEndBorder"; 94 | private const string Parid_clipStackPanel = "Z_Parid_clipStackPanel"; 95 | private const string Parid_clipOff = "Z_Parid_clipOff"; 96 | private const string Parid_clipStateTimeTextBlock = "Z_Parid_clipStateTimeTextBlock"; 97 | private const string Parid_clipEndTimeTextBlock = "Z_Parid_clipEndTimeTextBlock"; 98 | private const string Parid_cameraListBox = "Z_Parid_cameraListBox"; 99 | private const string Parid_downButtonListBox = "Z_Parid_downButtonListBox"; 100 | 101 | private const string GeometryDown = "M954.123536 509.086647 526.172791 932.999426c-8.074909 8.074909-20.185738 8.074909-28.260647 0L69.960375 509.086647c-12.110829-14.130835-4.427846-34.317597 14.130835-34.317597l215.994356 0L300.085566 107.149369c0-12.111852 10.093892-22.205745 22.204721-22.205745l379.50436 0c12.110829 0 22.204721 10.093892 22.204721 24.223704l0 365.601722 215.994356 0C958.159456 474.770074 966.234365 496.975818 954.123536 509.086647z"; 102 | private const string GeometryFavorite = "M1024 378.88l-314.647273-37.236364L512 0 314.647273 341.643636 0 378.88l236.450909 266.24L191.767273 1024 512 872.261818 832.232727 1024l-44.683636-378.88L1024 378.88z"; 103 | private const string GeometryOpen = "M512 68.191078c-245.204631 0-443.808922 198.60429-443.808922 443.808922s198.60429 443.808922 443.808922 443.808922 443.808922-198.60429 443.808922-443.808922S757.203608 68.191078 512 68.191078zM423.23842 711.713554 423.23842 312.285422l266.284739 199.713554L423.23842 711.713554z"; 104 | 105 | #endregion 106 | 107 | #region DependencyProperty 依赖项属性 108 | public static readonly DependencyProperty HistoryVideoSourceProperty = DependencyProperty.Register( 109 | "HisVideoSources", 110 | typeof(ObservableCollection), 111 | typeof(VideoStateAxisControl), 112 | new PropertyMetadata(new ObservableCollection(), OnHistoryVideoSourcesChanged)); 113 | 114 | public static readonly DependencyProperty StartTimeProperty = DependencyProperty.Register( 115 | "StartTime", 116 | typeof(DateTime), 117 | typeof(VideoStateAxisControl), 118 | new PropertyMetadata(OnTimeChanged)); 119 | 120 | public static readonly DependencyProperty EndTimeProperty = DependencyProperty.Register( 121 | "EndTime", 122 | typeof(DateTime), 123 | typeof(VideoStateAxisControl), 124 | new PropertyMetadata(OnTimeChanged)); 125 | 126 | public static readonly DependencyProperty AxisTimeProperty = DependencyProperty.Register( 127 | "AxisTime", 128 | typeof(DateTime), 129 | typeof(VideoStateAxisControl), 130 | new PropertyMetadata(OnAxisTimeChanged)); 131 | 132 | public static readonly DependencyProperty ClipStartTimeProperty = DependencyProperty.Register( 133 | "ClipStartTime", 134 | typeof(DateTime), 135 | typeof(VideoStateAxisControl), 136 | new PropertyMetadata(OnClipTimeChanged)); 137 | 138 | public static readonly DependencyProperty ClipEndTimeProperty = DependencyProperty.Register( 139 | "ClipEndTime", 140 | typeof(DateTime), 141 | typeof(VideoStateAxisControl), 142 | new PropertyMetadata(OnClipTimeChanged)); 143 | 144 | public static readonly DependencyProperty ClipOffProperty = DependencyProperty.Register( 145 | "ClipOff", 146 | typeof(bool), 147 | typeof(VideoStateAxisControl), 148 | new PropertyMetadata(OnClipOffChanged)); 149 | 150 | #endregion 151 | 152 | #region Property 属性关联字段 153 | 154 | 155 | /// 156 | /// 搜索历史视频开始时间 157 | /// 158 | public DateTime StartTime 159 | { 160 | get { return (DateTime)GetValue(StartTimeProperty); } 161 | set { SetValue(StartTimeProperty, value); } 162 | } 163 | 164 | /// 165 | /// 搜索历史视频结束时间 166 | /// 167 | public DateTime EndTime 168 | { 169 | get { return (DateTime)GetValue(EndTimeProperty); } 170 | set { SetValue(EndTimeProperty, value); } 171 | } 172 | 173 | /// 174 | /// 剪辑开启控制 175 | /// 176 | public bool ClipOff 177 | { 178 | get { return (bool)GetValue(ClipOffProperty); } 179 | set { SetValue(ClipOffProperty, value); } 180 | } 181 | 182 | /// 183 | /// 剪辑结束时间 184 | /// 185 | public DateTime ClipEndTime 186 | { 187 | get { return (DateTime)GetValue(ClipEndTimeProperty); } 188 | set { SetValue(ClipEndTimeProperty, value); } 189 | } 190 | 191 | /// 192 | /// 剪辑开始时间 193 | /// 194 | public DateTime ClipStartTime 195 | { 196 | get { return (DateTime)GetValue(ClipStartTimeProperty); } 197 | set { SetValue(ClipStartTimeProperty, value); } 198 | } 199 | 200 | /// 201 | /// 指针时间 202 | /// 203 | public DateTime AxisTime 204 | { 205 | get { return (DateTime)GetValue(AxisTimeProperty); } 206 | set { SetValue(AxisTimeProperty, value); } 207 | } 208 | 209 | /// 210 | /// 历史视频来源列表 211 | /// 212 | public ObservableCollection HisVideoSources 213 | { 214 | get { return (ObservableCollection)GetValue(HistoryVideoSourceProperty); } 215 | set { SetValue(HistoryVideoSourceProperty, value); } 216 | } 217 | 218 | /// 219 | /// 每小时占用时间轴的的宽度 220 | /// 221 | private double Dial_Cell_H 222 | { 223 | get { return _scrollViewer == null ? 0 : ((_scrollViewer.ActualWidth - 10) * Slider_Magnification) / 24; } 224 | } 225 | 226 | /// 227 | /// 每分钟占用时间轴的的宽度 228 | /// 229 | private double Dial_Cell_M 230 | { 231 | get { return Dial_Cell_H / 60; } 232 | } 233 | 234 | /// 235 | /// 每秒占用时间轴的的宽度 236 | /// 237 | private double Dial_Cell_S 238 | { 239 | get { return Dial_Cell_M / 60; } 240 | } 241 | 242 | /// 243 | /// 剪辑开始鼠标按下位置 244 | /// 245 | private double ClipStart_MouseDown_Offset = 0; 246 | 247 | /// 248 | /// 剪辑鼠标按下左坐标 249 | /// 250 | private double Start_MouseDown_ClipOffset = 0; 251 | 252 | /// 253 | /// 鼠标按下剪辑滑块宽度 254 | /// 255 | private double ClipStart_MouseDown_AreaWidth = 0; 256 | 257 | /// 258 | /// 时间轴缩放比例 259 | /// 260 | private double Slider_Magnification = 1; 261 | 262 | #endregion 263 | 264 | #region RouteEvent 路由事件 265 | 266 | public static readonly RoutedEvent AxisDownRoutedEvent = EventManager.RegisterRoutedEvent( 267 | "AxisDown", 268 | RoutingStrategy.Bubble, 269 | typeof(EventHandler), 270 | typeof(VideoStateAxisControl)); 271 | 272 | public static readonly RoutedEvent DragTimeLineRoutedEvent = EventManager.RegisterRoutedEvent( 273 | "DragTimeLine", 274 | RoutingStrategy.Bubble, 275 | typeof(EventHandler), 276 | typeof(VideoStateAxisControl)); 277 | 278 | /// 279 | /// 下载路由事件 280 | /// 281 | public event RoutedEventHandler AxisDown 282 | { 283 | add { this.AddHandler(AxisDownRoutedEvent, value); } 284 | remove { this.RemoveHandler(AxisDownRoutedEvent, value); } 285 | } 286 | 287 | /// 288 | /// 指针拖动事件 289 | /// 290 | public event RoutedEventHandler DragTimeLine 291 | { 292 | add { this.AddHandler(DragTimeLineRoutedEvent, value); } 293 | remove { this.RemoveHandler(DragTimeLineRoutedEvent, value); } 294 | } 295 | 296 | #endregion 297 | 298 | #region Method 方法 299 | 300 | /// 301 | /// 历史查询时间 - 改变 302 | /// 303 | /// 304 | /// 305 | private static void OnTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 306 | { 307 | VideoStateAxisControl AxisOb = d as VideoStateAxisControl; 308 | if (AxisOb != null) 309 | { 310 | AxisOb.InitializeAxis(); 311 | } 312 | } 313 | 314 | /// 315 | /// 历史视频来源 - 改变 316 | /// 317 | /// 318 | /// 319 | private static void OnHistoryVideoSourcesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 320 | { 321 | VideoStateAxisControl AxisOb = d as VideoStateAxisControl; 322 | if (AxisOb.HisVideoSources != null && AxisOb.HisVideoSources.Count() > 0) 323 | { 324 | AxisOb.InitializeAxis(); 325 | } 326 | AxisOb.HisVideoSources.CollectionChanged += (s, o) => 327 | { 328 | AxisOb.AddHisPie(); 329 | AxisOb.InitiaListBox_ScrollChanged(); 330 | }; 331 | } 332 | 333 | /// 334 | /// 指针时间刷新指针位置 335 | /// 336 | /// 337 | /// 338 | private static void OnAxisTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 339 | { 340 | VideoStateAxisControl AxisOb = d as VideoStateAxisControl; 341 | if (AxisOb != null && e.NewValue != e.OldValue) 342 | { 343 | AxisOb.RefreshTimeLineLeft((DateTime)e.NewValue); 344 | } 345 | } 346 | 347 | /// 348 | /// 剪辑时间变化,刷新剪辑控制条 349 | /// 350 | /// 351 | /// 352 | private static void OnClipTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 353 | { 354 | VideoStateAxisControl AxisOb = d as VideoStateAxisControl; 355 | if (AxisOb != null && e.NewValue != e.OldValue) 356 | { 357 | if (e.Property.Name == nameof(AxisOb.ClipStartTime)) 358 | { 359 | AxisOb.ClipStartTimeChanged((DateTime)e.NewValue); 360 | } 361 | if (e.Property.Name == nameof(AxisOb.ClipEndTime)) 362 | { 363 | AxisOb.ClipEndTimeChanged((DateTime)e.NewValue); 364 | } 365 | } 366 | } 367 | 368 | /// 369 | /// 剪辑开启控制源改变事件 370 | /// 371 | /// 372 | /// 373 | private static void OnClipOffChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 374 | { 375 | VideoStateAxisControl AxisOb = d as VideoStateAxisControl; 376 | if (AxisOb != null && e.NewValue != e.OldValue) 377 | { 378 | AxisOb.ClipOff = (bool)e.NewValue; 379 | AxisOb._clipOff.IsChecked = ((bool)e.NewValue) ? true : false; 380 | } 381 | } 382 | 383 | /// 384 | /// 构造函数初始化一些属性和样式 385 | /// 386 | public VideoStateAxisControl() 387 | { 388 | Loaded += delegate 389 | { 390 | InitializeAxis(); 391 | SizeChanged += delegate 392 | { 393 | InitializeAxis(); 394 | }; 395 | }; 396 | } 397 | 398 | /// 399 | /// 刷新指针位置 400 | /// 401 | /// 402 | private void RefreshTimeLineLeft(DateTime dt) 403 | { 404 | TimeSpan ts = dt - StartTime.Date; 405 | if (_timeLine != null) 406 | { 407 | Canvas.SetLeft(_timeLine, 408 | Dial_Cell_H * (ts.Days == 1 ? 23 : dt.Hour) + 409 | Dial_Cell_M * (ts.Days == 1 ? 59 : dt.Minute) + 410 | Dial_Cell_S * (ts.Days == 1 ? 59 : dt.Second)); 411 | _currentTime.Text = dt.ToString(" [ yyyy-MM-dd ] HH:mm:ss"); 412 | } 413 | } 414 | 415 | /// 416 | /// 剪辑鼠标弹起 417 | /// 418 | /// 419 | /// 420 | private void Clip_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 421 | { 422 | Border bor = sender as Border; 423 | if (bor != null) 424 | { 425 | bor.ReleaseMouseCapture(); 426 | } 427 | } 428 | 429 | /// 430 | /// 剪辑鼠标点击 431 | /// 432 | /// 433 | /// 434 | private void Clip_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 435 | { 436 | Border bor = sender as Border; 437 | if (bor != null) 438 | { 439 | bor.CaptureMouse(); 440 | ClipStart_MouseDown_Offset = e.GetPosition(_clipCanvas).X; 441 | Start_MouseDown_ClipOffset = _clipStackPanel.Margin.Left; 442 | ClipStart_MouseDown_AreaWidth = _clipStackPanel.Margin.Left + _clipStackPanel.ActualWidth; 443 | } 444 | } 445 | 446 | /// 447 | /// 剪辑鼠标移动,释放鼠标捕获 448 | /// 449 | /// 450 | /// 451 | private void Clip_MouseMove(object sender, MouseEventArgs e) 452 | { 453 | Border bor = sender as Border; 454 | if (bor != null && e.LeftButton == MouseButtonState.Pressed) 455 | { 456 | switch (bor.Name) 457 | { 458 | case Parid_clipStartBorder: 459 | ClipStart(e.GetPosition(_clipCanvas)); 460 | break; 461 | 462 | case Parid_clipEndBorder: 463 | ClipEnd(e.GetPosition(_clipCanvas)); 464 | break; 465 | 466 | case Parid_clipAreaBorder: 467 | MoveClipArea(e.GetPosition(_clipCanvas)); 468 | break; 469 | } 470 | MathClipTime(); 471 | } 472 | } 473 | 474 | /// 475 | /// 剪辑开始滑块增量 476 | /// 477 | /// 478 | private void ClipStart(Point pt) 479 | { 480 | if (pt.X >= 0) 481 | { 482 | double clipWidth = ClipStart_MouseDown_AreaWidth - (Start_MouseDown_ClipOffset + (pt.X - ClipStart_MouseDown_Offset) < 0 ? 0 : 483 | Start_MouseDown_ClipOffset + (pt.X - ClipStart_MouseDown_Offset) > _clipCanvas.ActualWidth - _clipAreaBorder.Width ? 484 | _axisCanvas.ActualWidth - _clipAreaBorder.Width : 485 | Start_MouseDown_ClipOffset + (pt.X - ClipStart_MouseDown_Offset)) - 10; 486 | _clipAreaBorder.Width = clipWidth <= 0 ? 0 : clipWidth; 487 | if (clipWidth >= 0) 488 | { 489 | MoveClipArea(pt); 490 | } 491 | } 492 | } 493 | 494 | /// 495 | /// 剪辑结束滑块增量 496 | /// 497 | private void ClipEnd(Point pt) 498 | { 499 | double clipWidth = pt.X - _clipStackPanel.Margin.Left; 500 | _clipAreaBorder.Width = clipWidth <= 0 ? 0 : 501 | clipWidth > _axisCanvas.ActualWidth - _clipStackPanel.Margin.Left ? 502 | _axisCanvas.ActualWidth - _clipStackPanel.Margin.Left : clipWidth; 503 | } 504 | 505 | /// 506 | /// 剪辑滚动滑块 507 | /// 508 | /// 509 | private void MoveClipArea(Point pt) 510 | { 511 | double clipLeft = Start_MouseDown_ClipOffset + (pt.X - ClipStart_MouseDown_Offset) < 0 ? 0 : 512 | Start_MouseDown_ClipOffset + (pt.X - ClipStart_MouseDown_Offset) > _clipCanvas.ActualWidth - _clipAreaBorder.Width ? 513 | _axisCanvas.ActualWidth - _clipAreaBorder.Width : 514 | Start_MouseDown_ClipOffset + (pt.X - ClipStart_MouseDown_Offset); 515 | _clipStackPanel.Margin = new Thickness(clipLeft, 0, 0, 0); 516 | } 517 | 518 | /// 519 | /// 时间缩放滑块事件 520 | /// 521 | /// 522 | /// 523 | private void _zoomSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) 524 | { 525 | Slider_Magnification = Math.Round(e.NewValue, 2); 526 | InitializeAxis(); 527 | } 528 | 529 | /// 530 | /// 滚动重置时间刻度位置 531 | /// 532 | /// 533 | /// 534 | private void scrollViewer_Changed(object sender, ScrollChangedEventArgs e) 535 | { 536 | _timeLine.Margin = new Thickness(0, _scrollViewer.VerticalOffset, 0, 0); 537 | _axisCanvasTimeText.Margin = new Thickness(0, _scrollViewer.VerticalOffset, 0, 0); 538 | _axisCanvas.Margin = new Thickness(0, _scrollViewer.VerticalOffset, 0, 0); 539 | _clipCanvas.Margin = new Thickness(0, _scrollViewer.VerticalOffset, 0, 0); 540 | 541 | 542 | if (_cameraScrollViewer != null) 543 | { 544 | double offset = _scrollViewer.VerticalOffset / _scrollViewer.ScrollableHeight * _cameraScrollViewer.ScrollableHeight; 545 | _cameraScrollViewer.ScrollToVerticalOffset(double.IsNaN(offset) ? 0 : offset); 546 | } 547 | if (_downScrollViewer != null) 548 | { 549 | double offset = _scrollViewer.VerticalOffset / _scrollViewer.ScrollableHeight * _downScrollViewer.ScrollableHeight; 550 | _downScrollViewer.ScrollToVerticalOffset(double.IsNaN(offset) ? 0 : offset); 551 | } 552 | } 553 | 554 | /// 555 | /// 相机列表ListBox的ScrollerViewerChanged事件 556 | /// 557 | /// 558 | /// 559 | private void _cameraScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) 560 | { 561 | if (_scrollViewer != null) 562 | { 563 | double offset = _cameraScrollViewer.VerticalOffset / _cameraScrollViewer.ScrollableHeight * _scrollViewer.ScrollableHeight; 564 | _scrollViewer.ScrollToVerticalOffset(double.IsNaN(offset) ? 0 : offset); 565 | } 566 | if (_downScrollViewer != null) 567 | { 568 | _downScrollViewer.ScrollToVerticalOffset(_cameraScrollViewer.VerticalOffset); 569 | } 570 | } 571 | 572 | /// 573 | /// 下载列表ListBox的ScrollerViewerChanged事件 574 | /// 575 | /// 576 | /// 577 | private void _downScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) 578 | { 579 | if (_scrollViewer != null) 580 | { 581 | double offset = _downScrollViewer.VerticalOffset / _downScrollViewer.ScrollableHeight * _scrollViewer.ScrollableHeight; 582 | _scrollViewer.ScrollToVerticalOffset(double.IsNaN(offset) ? 0 : offset); 583 | } 584 | if (_cameraScrollViewer != null) 585 | { 586 | _cameraScrollViewer.ScrollToVerticalOffset(_downScrollViewer.VerticalOffset); 587 | } 588 | } 589 | 590 | /// 591 | /// 指针移动 592 | /// 593 | /// 594 | /// 595 | private void timePoint_MouseMove(object sender, MouseEventArgs s) 596 | { 597 | if (Mouse.LeftButton == MouseButtonState.Pressed) 598 | { 599 | double delta = s.GetPosition(_timePanel).X; 600 | double timePointMaxLeft = _timePanel.ActualWidth - _timePoint.ActualWidth; 601 | Canvas.SetLeft(_timeLine, delta = delta < 0 ? 0 : (delta > timePointMaxLeft ? timePointMaxLeft : delta)); 602 | TimeLine_Resver(delta); 603 | } 604 | } 605 | 606 | /// 607 | /// 刷新时间指示器坐标位置 608 | /// 609 | /// 鼠标位于Canvas坐标X 610 | private void TimeLine_Resver(double delta) 611 | { 612 | double timePointMaxLeft = _timePanel.ActualWidth - _timePoint.ActualWidth; 613 | double currentTimeMaxLeft = _timePanel.ActualWidth - _currentTime.ActualWidth; 614 | _currentTime.Text = (AxisTime = XToDateTime(delta < 0 ? 0 : (delta > timePointMaxLeft ? timePointMaxLeft : delta))).ToString(" [ yyyy-MM-dd ] HH:mm:ss"); 615 | _currentTime.Margin = delta < currentTimeMaxLeft ? 616 | new Thickness(delta < 0 ? 10 : delta + 10, 2, 0, 0) : 617 | new Thickness(delta > timePointMaxLeft ? timePointMaxLeft - _currentTime.ActualWidth : delta - _currentTime.ActualWidth, 2, 0, 0); 618 | } 619 | 620 | /// 621 | /// 剪辑控制开启Checked事件 622 | /// 623 | /// 624 | /// 625 | private void Clip_UnChecked_Checked(object sender, RoutedEventArgs e) 626 | { 627 | CheckBox check = sender as CheckBox; 628 | if (check != null) 629 | { 630 | ClipOff = check.IsChecked == null || check.IsChecked == false ? false : true; 631 | } 632 | } 633 | 634 | /// 635 | /// 指针按下 636 | /// 637 | /// 638 | /// 639 | private void timePoint_MouseLeftButtonDown(object sender, MouseButtonEventArgs s) 640 | { 641 | _currentTime.Visibility = Visibility.Visible; 642 | _timePoint.CaptureMouse(); 643 | } 644 | 645 | /// 646 | /// 发布指针拖动路由事件 647 | /// 648 | private void SendDragTimeLineRoutedEvent() 649 | { 650 | VideoStateAxisRoutedEventArgs args = new VideoStateAxisRoutedEventArgs(DragTimeLineRoutedEvent, this) 651 | { 652 | TimeLine = AxisTime 653 | }; 654 | this.RaiseEvent(args); 655 | } 656 | 657 | /// 658 | /// 指针弹起 659 | /// 660 | /// 661 | /// 662 | private void timePoint_MouseLeftButtonUp(object sender, MouseButtonEventArgs s) 663 | { 664 | _currentTime.Visibility = Visibility.Collapsed; 665 | _timePoint.ReleaseMouseCapture(); 666 | SendDragTimeLineRoutedEvent(); 667 | } 668 | 669 | /// 670 | /// 计算指针拖动的显示时间 671 | /// 672 | /// 指针在Canvas容器中的Left坐标值 673 | private DateTime XToDateTime(double point_x) 674 | { 675 | DateTime dt = StartTime.Date; 676 | double time; 677 | int H, M, S; 678 | time = point_x / Dial_Cell_H; 679 | H = (int)(time); 680 | time = (time - H) * 60; 681 | M = (int)(time); 682 | S = (int)((time - M) * 60); 683 | return dt.AddHours(H).AddMinutes(M).AddSeconds(S); 684 | } 685 | 686 | /// 687 | /// 初始化 688 | /// 689 | private void InitializeAxis() 690 | { 691 | AddTimeTextBlock(); 692 | AddTimeLine(); 693 | AddHisPie(); 694 | ClipStartTimeChanged(ClipStartTime); 695 | ClipEndTimeChanged(ClipEndTime); 696 | InitiaClipTime(); 697 | InitiaListBox_ScrollChanged(); 698 | InitializationNewtTimeLine(); 699 | } 700 | 701 | /// 702 | /// 初始化剪辑时间 703 | /// 704 | private void InitiaClipTime() 705 | { 706 | ClipStartTime = ClipStartTime.Year == DateTime.Parse("0001/1/1 0:00:00").Year ? StartTime.Date : ClipStartTime; 707 | ClipEndTime = ClipEndTime.Year == DateTime.Parse("0001/1/1 0:00:00").Year ? StartTime.Date.AddDays(1) : ClipEndTime; 708 | } 709 | 710 | /// 711 | /// 初始化相机列表ListBox的ScrollerViewerChanged事件 712 | /// 713 | private void InitiaListBox_ScrollChanged() 714 | { 715 | if (_cameraListBox != null) 716 | { 717 | Decorator carmeraborder = VisualTreeHelper.GetChild(_cameraListBox, 0) as Decorator; 718 | if (carmeraborder != null) 719 | { 720 | _cameraScrollViewer = carmeraborder.Child as ScrollViewer; 721 | if (_cameraScrollViewer != null) 722 | { 723 | _cameraScrollViewer.ScrollChanged += _cameraScrollViewer_ScrollChanged; 724 | } 725 | } 726 | } 727 | 728 | if (_downButtonListBox != null) 729 | { 730 | Decorator downborder = VisualTreeHelper.GetChild(_downButtonListBox, 0) as Decorator; 731 | if (downborder != null) 732 | { 733 | _downScrollViewer = downborder.Child as ScrollViewer; 734 | if (_downScrollViewer != null) 735 | { 736 | _downScrollViewer.ScrollChanged += _downScrollViewer_ScrollChanged; 737 | } 738 | } 739 | } 740 | } 741 | 742 | /// 743 | /// 计算剪辑时间 744 | /// 745 | private void MathClipTime() 746 | { 747 | ClipStartTime = XToDateTime(_clipStackPanel.Margin.Left); 748 | ClipEndTime = XToDateTime(_clipStackPanel.Margin.Left + _clipAreaBorder.ActualWidth); 749 | } 750 | 751 | /// 752 | /// 重新计算剪辑时间为准的剪辑条左坐标 753 | /// 754 | private void ClipStartTimeChanged(DateTime dt) 755 | { 756 | TimeSpan ts = dt - StartTime.Date; 757 | if (ts.Days <= 1 && ts.Seconds >= 0 && _clipStackPanel != null) 758 | { 759 | double left = Dial_Cell_H * (ts.Days == 1 ? 23 : dt.Hour) + Dial_Cell_M * (ts.Days == 1 ? 59 : dt.Minute) + Dial_Cell_S * (ts.Days == 1 ? 59 : dt.Second); 760 | _clipStackPanel.Margin = new Thickness(left, 0, 0, 0); 761 | } 762 | } 763 | 764 | /// 765 | /// 重新计算剪辑时间为准的剪辑条宽度 766 | /// 767 | /// 768 | private void ClipEndTimeChanged(DateTime dt) 769 | { 770 | TimeSpan ts = dt - ClipStartTime; 771 | if (ts.Days <= 1 && ts.Seconds >= 0 && _clipAreaBorder != null) 772 | { 773 | double width = Dial_Cell_H * (ts.Days == 1 ? 23 : ts.Hours) + Dial_Cell_M * (ts.Days == 1 ? 59 : ts.Minutes) + Dial_Cell_S * (ts.Days == 1 ? 59 : ts.Seconds); 774 | _clipAreaBorder.Width = width; 775 | } 776 | } 777 | 778 | /// 779 | /// 初始化指针位置 780 | /// 781 | private void InitializationNewtTimeLine() 782 | { 783 | if (_timeLine != null && !double.IsNaN(Canvas.GetLeft(_timeLine))) 784 | { 785 | RefreshTimeLineLeft(AxisTime); 786 | } 787 | } 788 | 789 | /// 790 | /// 初始化时间刻度文字 791 | /// 792 | /// 需要填充的时间文字数量 793 | private void AddTimeTextBlock() 794 | { 795 | if (_axisCanvasTimeText != null) 796 | { 797 | _axisCanvasTimeText.Width = (_scrollViewer.ActualWidth - 10) * Slider_Magnification; 798 | _axisCanvasTimeText.Children.Clear(); 799 | for (int i = 0; i < 24; i++) 800 | { 801 | _axisCanvasTimeText.Children.Add(( 802 | new TextBlock() 803 | { 804 | Text = i.ToString().PadLeft(2, '0') + ":00", 805 | Margin = new Thickness(Dial_Cell_H * i, 2, 0, 0) 806 | })); 807 | } 808 | } 809 | } 810 | 811 | /// 812 | /// 初始化时间刻度 813 | /// 814 | /// 需要填充的时间刻度数量 815 | private void AddTimeLine() 816 | { 817 | if (_axisCanvas != null) 818 | { 819 | _axisCanvas.Children.Clear(); 820 | for (int i = 0; i < 24; i++) 821 | { 822 | _axisCanvas.Children.Add(new Line() 823 | { 824 | X1 = Dial_Cell_H * i, 825 | Y1 = 0, 826 | X2 = Dial_Cell_H * i, 827 | Y2 = 5, 828 | StrokeThickness = 1 829 | }); 830 | } 831 | } 832 | } 833 | 834 | /// 835 | /// 初始化时间轴 836 | /// 837 | private void AddHisPie() 838 | { 839 | if (_videoHistoryPanel != null && HisVideoSources != null && HisVideoSources.Count() > 0) 840 | { 841 | _videoHistoryPanel.Children.Clear(); 842 | foreach (var item in HisVideoSources) 843 | { 844 | Dictionary, bool> dic = MathToTimeSp(item.AxisHistoryTimeList); 845 | DisplayData(dic); 846 | } 847 | } 848 | } 849 | 850 | /// 851 | /// 计算填充时间轴查询结果 852 | /// 853 | private void DisplayData(Dictionary, bool> dic) 854 | { 855 | DateTime serTime = StartTime; 856 | Canvas TimeCanvas = new Canvas() { Width = (_scrollViewer.ActualWidth - 10) * Slider_Magnification }; 857 | foreach (var item in dic) 858 | { 859 | TimeCanvas.Children.Add(new Rectangle() 860 | { 861 | Width = item.Key.Value * Dial_Cell_M, 862 | Height = item.Value ? 16 : 0, 863 | Margin = new Thickness(serTime.Hour * Dial_Cell_H + serTime.Minute * Dial_Cell_M + serTime.Second * Dial_Cell_S, 0, 0, 0) 864 | }); 865 | serTime = serTime.AddMinutes(item.Key.Value); 866 | } 867 | _videoHistoryPanel.Children.Add(TimeCanvas); 868 | } 869 | 870 | /// 871 | /// 计算断续时间轴 872 | /// 873 | /// 874 | /// 875 | private Dictionary, bool> MathToTimeSp(char[] region) 876 | { 877 | Dictionary, bool> dic = new Dictionary, bool>(); 878 | string regStr = new string(region.Select(x => x == '\0' ? x = '0' : '1').ToArray()); 879 | foreach (Match item in Regex.Matches(regStr, "(.)\\1*")) 880 | { 881 | if (item.Success) 882 | { 883 | dic.Add(new KeyValuePair(dic.Count + 1, item.Value.Length), item.Value.Contains('1') ? true : false); 884 | } 885 | } 886 | return dic; 887 | } 888 | 889 | /// 890 | /// 初始化下载数据模板 891 | /// 892 | private void Down_ListBox_Template() 893 | { 894 | DataTemplate dataTemplate = new DataTemplate(); 895 | FrameworkElementFactory topElement = CreateTopElement(); 896 | 897 | FrameworkElementFactory downPath = CreatePathElement(GeometryDown, "下载历史"); 898 | FrameworkElementFactory downViewBox = CreateViewBoxElement(VideoAxisActionType.Dwon.ToString(), downPath); 899 | topElement.AppendChild(downViewBox); 900 | 901 | FrameworkElementFactory favoritePath = CreatePathElement(GeometryFavorite, "收藏历史"); 902 | FrameworkElementFactory favoriteViewBox = CreateViewBoxElement(VideoAxisActionType.Favorite.ToString(), favoritePath); 903 | topElement.AppendChild(favoriteViewBox); 904 | 905 | FrameworkElementFactory openPath = CreatePathElement(GeometryOpen, "打开视频"); 906 | FrameworkElementFactory openViewBox = CreateViewBoxElement(VideoAxisActionType.Open.ToString(), openPath); 907 | topElement.AppendChild(openViewBox); 908 | 909 | dataTemplate.VisualTree = topElement; 910 | _downButtonListBox.ItemTemplate = dataTemplate; 911 | } 912 | 913 | /// 914 | /// 创建顶层数据模板容器 915 | /// 916 | /// 917 | private FrameworkElementFactory CreateTopElement() 918 | { 919 | FrameworkElementFactory frameworkElementFactory = new FrameworkElementFactory(typeof(StackPanel)); 920 | frameworkElementFactory.SetValue(StackPanel.HeightProperty, 16.00); 921 | frameworkElementFactory.SetValue(StackPanel.MarginProperty, new Thickness(0, 4, 5, 0)); 922 | frameworkElementFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal); 923 | return frameworkElementFactory; 924 | } 925 | 926 | /// 927 | /// 创建Path元素模板 928 | /// 929 | /// 930 | /// 931 | /// 932 | private FrameworkElementFactory CreatePathElement(string GeometryPath, string ToolTipStr) 933 | { 934 | FrameworkElementFactory path = new FrameworkElementFactory(typeof(Path)); 935 | path.SetValue(CursorProperty, Cursors.Hand); 936 | path.SetValue(Path.DataProperty, Geometry.Parse(GeometryPath)); 937 | path.SetValue(Path.FillProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#c8c7c3"))); 938 | path.SetValue(ToolTipProperty, ToolTipStr); 939 | return path; 940 | } 941 | 942 | /// 943 | /// 创建ViewBox元素模板 944 | /// 945 | /// 946 | /// 947 | /// 948 | /// 949 | private FrameworkElementFactory CreateViewBoxElement(string NameStr, FrameworkElementFactory pathChild) 950 | { 951 | FrameworkElementFactory viewBox = new FrameworkElementFactory(typeof(Viewbox)); 952 | viewBox.SetValue(HeightProperty, 14.00); 953 | viewBox.SetValue(WidthProperty, 14.00); 954 | viewBox.SetValue(MarginProperty, new Thickness(10, 0, 0, 2)); 955 | viewBox.SetValue(NameProperty, NameStr); 956 | viewBox.AddHandler(MouseLeftButtonDownEvent, new MouseButtonEventHandler(viewBox_LeftMouseButtonDown)); 957 | viewBox.AppendChild(pathChild); 958 | return viewBox; 959 | } 960 | 961 | /// 962 | /// 模板触发路由事件 963 | /// 964 | /// 965 | /// 966 | private void viewBox_LeftMouseButtonDown(object sender, MouseButtonEventArgs e) 967 | { 968 | Viewbox viewBox = sender as Viewbox; 969 | VideoStateItem videoState = viewBox.DataContext as VideoStateItem; 970 | if (videoState != null && viewBox != null) 971 | { 972 | VideoStateAxisRoutedEventArgs args = new VideoStateAxisRoutedEventArgs(AxisDownRoutedEvent, this) 973 | { 974 | CameraChecked = videoState.CameraChecked, 975 | DownAndFavoirteHaveVideo = DownAndFavoriteHaveVideo(videoState.AxisHistoryTimeList) 976 | }; 977 | switch ((VideoAxisActionType)Enum.Parse(typeof(VideoAxisActionType), viewBox.Name)) 978 | { 979 | case VideoAxisActionType.Dwon: 980 | args.ActionType = VideoAxisActionType.Dwon; 981 | break; 982 | case VideoAxisActionType.Favorite: 983 | args.ActionType = VideoAxisActionType.Favorite; 984 | break; 985 | case VideoAxisActionType.Open: 986 | args.ActionType = VideoAxisActionType.Open; 987 | break; 988 | } 989 | this.RaiseEvent(args); 990 | } 991 | } 992 | 993 | /// 994 | /// 判断是否有视频 995 | /// 996 | /// 997 | /// 998 | private bool DownAndFavoriteHaveVideo(char[] VideoList) 999 | { 1000 | if (!ClipOff) 1001 | { 1002 | return VideoList.Select(x => x == '\0' ? x = '0' : '1').ToArray().Contains('1') ? true : false; 1003 | } 1004 | else 1005 | { 1006 | Dictionary, bool> dic = MathToTimeSp(VideoList); 1007 | DateTime serTime = StartTime; 1008 | List booList = new List(); 1009 | foreach (var item in dic) 1010 | { 1011 | DateTime end_Time = serTime.AddMinutes(item.Key.Value); 1012 | booList.Add(((serTime < ClipStartTime && ClipStartTime < end_Time) || (serTime < ClipEndTime && ClipEndTime < end_Time)) && item.Value ? true : false); 1013 | serTime = serTime.AddMinutes(item.Key.Value); 1014 | } 1015 | return booList.Contains(true) ? true : false; 1016 | } 1017 | } 1018 | 1019 | /// 1020 | /// 获得实例项 1021 | /// 1022 | public override void OnApplyTemplate() 1023 | { 1024 | _timePanel = GetTemplateChild(Parid_timePanel) as Canvas; 1025 | _timeLine = GetTemplateChild(Parid_timeLine) as Canvas; 1026 | _axisCanvas = GetTemplateChild(Parid_axisCanvas) as Canvas; 1027 | _videoHistoryPanel = GetTemplateChild(Parid_videoHistoryPanel) as StackPanel; 1028 | _axisCanvasTimeText = GetTemplateChild(Parid__axisCanvasTimeText) as Canvas; 1029 | _clipCanvas = GetTemplateChild(Parid_clipCanvas) as Canvas; 1030 | _clipStackPanel = GetTemplateChild(Parid_clipStackPanel) as StackPanel; 1031 | if ((_clipOff = GetTemplateChild(Parid_clipOff) as CheckBox) != null) 1032 | { 1033 | _clipOff.Checked += new RoutedEventHandler(Clip_UnChecked_Checked); 1034 | _clipOff.Unchecked += new RoutedEventHandler(Clip_UnChecked_Checked); 1035 | } 1036 | if ((_zoomSlider = GetTemplateChild(Parid_zoomSlider) as Slider) != null) 1037 | { 1038 | _zoomSlider.ValueChanged += new RoutedPropertyChangedEventHandler(_zoomSlider_ValueChanged); 1039 | } 1040 | if ((_timePoint = GetTemplateChild(Parid_timePoint) as Grid) != null) 1041 | { 1042 | _timePoint.MouseLeftButtonDown += new MouseButtonEventHandler(timePoint_MouseLeftButtonDown); 1043 | _timePoint.MouseLeftButtonUp += new MouseButtonEventHandler(timePoint_MouseLeftButtonUp); 1044 | _timePoint.MouseMove += new MouseEventHandler(timePoint_MouseMove); 1045 | } 1046 | if ((_scrollViewer = GetTemplateChild(Parid_scrollViewer) as ScrollViewer) != null) 1047 | { 1048 | _scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer_Changed); 1049 | } 1050 | if ((_currentTime = GetTemplateChild(Parid_currentTime) as TextBlock) != null) 1051 | { 1052 | _currentTime.Text = StartTime.ToString("yyyy-MM-dd 00:00:00"); 1053 | } 1054 | if ((_clipEndBorder = GetTemplateChild(Parid_clipEndBorder) as Border) != null) 1055 | { 1056 | _clipEndBorder.MouseLeftButtonDown += new MouseButtonEventHandler(Clip_MouseLeftButtonDown); 1057 | _clipEndBorder.MouseMove += new MouseEventHandler(Clip_MouseMove); 1058 | _clipEndBorder.MouseLeftButtonUp += new MouseButtonEventHandler(Clip_MouseLeftButtonUp); 1059 | } 1060 | if ((_clipAreaBorder = GetTemplateChild(Parid_clipAreaBorder) as Border) != null) 1061 | { 1062 | _clipAreaBorder.MouseLeftButtonDown += new MouseButtonEventHandler(Clip_MouseLeftButtonDown); 1063 | _clipAreaBorder.MouseMove += new MouseEventHandler(Clip_MouseMove); 1064 | _clipAreaBorder.MouseLeftButtonUp += new MouseButtonEventHandler(Clip_MouseLeftButtonUp); 1065 | } 1066 | if ((_clipStartBorder = GetTemplateChild(Parid_clipStartBorder) as Border) != null) 1067 | { 1068 | _clipStartBorder.MouseLeftButtonDown += new MouseButtonEventHandler(Clip_MouseLeftButtonDown); 1069 | _clipStartBorder.MouseMove += new MouseEventHandler(Clip_MouseMove); 1070 | _clipStartBorder.MouseLeftButtonUp += new MouseButtonEventHandler(Clip_MouseLeftButtonUp); 1071 | } 1072 | if ((_clipStateTimeTextBlock = GetTemplateChild(Parid_clipStateTimeTextBlock) as TextBlock) != null) 1073 | { 1074 | Binding binding = new Binding("ClipStartTime") { Source = this, StringFormat = " [ yyyy-MM-dd ] HH:mm:ss " }; 1075 | _clipStateTimeTextBlock.SetBinding(TextBlock.TextProperty, binding); 1076 | } 1077 | if ((_clipEndTimeTextBlock = GetTemplateChild(Parid_clipEndTimeTextBlock) as TextBlock) != null) 1078 | { 1079 | Binding binding = new Binding("ClipEndTime") { Source = this, StringFormat = " [ yyyy-MM-dd ] HH:mm:ss " }; 1080 | _clipEndTimeTextBlock.SetBinding(TextBlock.TextProperty, binding); 1081 | } 1082 | if ((_cameraListBox = GetTemplateChild(Parid_cameraListBox) as ListBox) != null) 1083 | { 1084 | Binding binding = new Binding("HisVideoSources") { Source = this }; 1085 | _cameraListBox.SetBinding(ListBox.ItemsSourceProperty, binding); 1086 | } 1087 | if ((_downButtonListBox = GetTemplateChild(Parid_downButtonListBox) as ListBox) != null) 1088 | { 1089 | Binding binding = new Binding("HisVideoSources") { Source = this }; 1090 | _downButtonListBox.SetBinding(ListBox.ItemsSourceProperty, binding); 1091 | Down_ListBox_Template(); 1092 | } 1093 | } 1094 | 1095 | /// 1096 | /// 将原始控件的样式覆盖 1097 | /// 1098 | static VideoStateAxisControl() 1099 | { 1100 | DefaultStyleKeyProperty.OverrideMetadata(typeof(VideoStateAxisControl), new FrameworkPropertyMetadata(typeof(VideoStateAxisControl))); 1101 | } 1102 | 1103 | #endregion 1104 | } 1105 | 1106 | /// 1107 | /// 时间轴事件参数类 1108 | /// 1109 | public class VideoStateAxisRoutedEventArgs : RoutedEventArgs 1110 | { 1111 | /// 1112 | /// 基类构造函数 1113 | /// 1114 | /// 1115 | /// 1116 | public VideoStateAxisRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } 1117 | 1118 | /// 1119 | /// 事件类型 1120 | /// 1121 | public VideoAxisActionType ActionType { get; set; } 1122 | 1123 | /// 1124 | /// 相机是否选中 1125 | /// 1126 | public bool CameraChecked { get; set; } 1127 | 1128 | /// 1129 | /// 指针时间 1130 | /// 1131 | public DateTime TimeLine { get; set; } 1132 | 1133 | /// 1134 | /// 下载或者收藏范围内是否有视频 1135 | /// 1136 | public bool DownAndFavoirteHaveVideo { get; set; } 1137 | } 1138 | 1139 | /// 1140 | /// 时间轴控件事件类型 1141 | /// 1142 | public enum VideoAxisActionType 1143 | { 1144 | [Description("下载")] 1145 | Dwon, 1146 | 1147 | [Description("收藏")] 1148 | Favorite, 1149 | 1150 | [Description("打开")] 1151 | Open 1152 | } 1153 | 1154 | /// 1155 | /// 时间轴对象 1156 | /// 1157 | public class VideoStateItem : INotifyPropertyChanged 1158 | { 1159 | private string _cameraName; 1160 | public string CameraName 1161 | { 1162 | get => _cameraName; 1163 | set { _cameraName = value;OnPropertyChanged("CameraName"); } 1164 | } 1165 | 1166 | private bool _cameraChedcked; 1167 | /// 1168 | /// 相机是否选中 1169 | /// 1170 | public bool CameraChecked 1171 | { 1172 | get => _cameraChedcked; 1173 | set { _cameraChedcked = value; OnPropertyChanged("CameraChecked"); } 1174 | } 1175 | 1176 | private char[] _axisHistoryTimeList; 1177 | /// 1178 | /// 相机历史视频视频时间集 1179 | /// 1180 | public char[] AxisHistoryTimeList 1181 | { 1182 | get => _axisHistoryTimeList; 1183 | set { _axisHistoryTimeList = value; OnPropertyChanged("AxisHistoryTimeList"); } 1184 | } 1185 | 1186 | public event PropertyChangedEventHandler PropertyChanged; 1187 | 1188 | private void OnPropertyChanged(string propertyName) 1189 | { 1190 | PropertyChangedEventHandler handler = this.PropertyChanged; 1191 | if (handler != null) 1192 | { 1193 | handler(this, new PropertyChangedEventArgs(propertyName)); 1194 | } 1195 | } 1196 | } 1197 | } 1198 | --------------------------------------------------------------------------------