Commit 5b3bb857 by liulongfei

初始化项目

parents
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("VIZ.Framework.Common.Resource")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.Common.Resource")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace VIZ.Framework.Common.Resource.Properties {
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[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>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </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("VIZ.Framework.Common.Resource.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
<?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>
\ No newline at end of file
//------------------------------------------------------------------------------
// <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 VIZ.Framework.Common.Resource.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.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;
}
}
}
}
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
\ No newline at end of file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="VMessageBox_Button_Yes" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="140"></Setter>
<Setter Property="Height" Value="45"></Setter>
<Setter Property="Margin" Value="10,0,10,0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" CornerRadius="10" Background="#aa007cff">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" TextElement.FontSize="18" TextElement.Foreground="White"></ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#ff007cff"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="VMessageBox_Button_Cancel" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="140"></Setter>
<Setter Property="Height" Value="45"></Setter>
<Setter Property="Margin" Value="10,0,10,0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" CornerRadius="10" Background="#aadcdcdc">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" TextElement.FontSize="18" TextElement.Foreground="Black"></ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#ffdcdcdc"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="Button_Close" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="50"></Setter>
<Setter Property="Height" Value="40"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" BorderBrush="Transparent" BorderThickness="1" Background="Transparent">
<Grid x:Name="grid" HorizontalAlignment="Center" VerticalAlignment="Center" Width="20" Height="20" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<RotateTransform Angle="0"/>
</Grid.RenderTransform>
<Rectangle Width="20" Height="2" Fill="White" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<RotateTransform Angle="45"/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Width="20" Height="2" Fill="White" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<RotateTransform Angle="-45"/>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#22ffffff"></Setter>
</Trigger>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="grid" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
Duration="00:00:00.3" To="180"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="grid" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
Duration="00:00:00.3" To="0"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="Button_Min" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="50"></Setter>
<Setter Property="Height" Value="40"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" BorderBrush="Transparent" BorderThickness="1" Background="Transparent">
<Grid x:Name="grid" HorizontalAlignment="Center" VerticalAlignment="Center" Width="20" Height="20" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<RotateTransform Angle="0"/>
</Grid.RenderTransform>
<Rectangle Width="20" Height="2" Fill="White" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5"></Rectangle>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#22ffffff"></Setter>
</Trigger>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="grid" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
Duration="00:00:00.3" To="180"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="grid" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
Duration="00:00:00.3" To="0"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="Button_Setting" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="50"></Setter>
<Setter Property="Height" Value="40"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" BorderBrush="Transparent" BorderThickness="1" Background="Transparent">
<Grid x:Name="grid" HorizontalAlignment="Center" VerticalAlignment="Center" Width="20" Height="20" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<RotateTransform Angle="0"/>
</Grid.RenderTransform>
<Image Width="20" Height="20" HorizontalAlignment="Center" VerticalAlignment="Center"
Source="/VIZ.Framework.Common.Resource;component/Icons/setting_32x32.png"></Image>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#22ffffff"></Setter>
</Trigger>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="grid" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
Duration="00:00:00.3" To="180"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="grid" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
Duration="00:00:00.3" To="0"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="ListBoxItem" x:Key="ListBoxItem_None">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="Transparent">
<ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.7"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="ListBoxItem" x:Key="ListBoxItem_None_IsSelected">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="IsSelected" Value="{Binding Path=IsSelected,Mode=TwoWay}"></Setter>
<Setter Property="Background" Value="#660000ff"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Border x:Name="bd" Opacity="0" Background="{TemplateBinding Background}"></Border>
<Border x:Name="bdSelected" Opacity="0" Background="{TemplateBinding Background}"></Border>
<ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Opacity" Value="0.2"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bdSelected" Property="Opacity" Value="0.2"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.7"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="ListBox" x:Key="ListBox_None">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="ItemContainerStyle" Value="{StaticResource ListBoxItem_None}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.7"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
\ No newline at end of file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
xmlns:common="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common">
<core:Bool2VisibilityConverter x:Key="Bool2VisibilityConverter" TrueVisibility="Visible" FalseVisibility="Collapsed"></core:Bool2VisibilityConverter>
<Style TargetType="RepeatButton" x:Key="NumberBox_Up">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border x:Name="border" Background="Transparent">
<Image Source="/VIZ.Framework.Common.Resource;component/Icons/triangle_up_16x16.png" Width="6" Height="13"
VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,5"></Image>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#22FFFFFF"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="RepeatButton" x:Key="NumberBox_Down">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border x:Name="border" Background="Transparent">
<Image Source="/VIZ.Framework.Common.Resource;component/Icons/triangle_down_16x16.png" Width="6" Height="13"
VerticalAlignment="Top" HorizontalAlignment="Center" Margin="0,5,0,0"></Image>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#22FFFFFF"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="common:NumberBox">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Background" Value="#ff0e131e"/>
<Setter Property="BorderBrush" Value="#ff3d4758"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="16"></Setter>
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="common:NumberBox">
<Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" Margin="5,0,5,0"
VerticalScrollBarVisibility="Hidden" VerticalContentAlignment="Center" Grid.RowSpan="2"/>
<RepeatButton x:Name="PART_Up" Style="{StaticResource NumberBox_Up}" Width="30"
Visibility="{TemplateBinding IsShowUpAndDownButton,Converter={StaticResource Bool2VisibilityConverter}}"
Grid.Column="1" Grid.Row="0" Content="Up"></RepeatButton>
<RepeatButton x:Name="PART_Down" Style="{StaticResource NumberBox_Down}" Width="30"
Visibility="{TemplateBinding IsShowUpAndDownButton,Converter={StaticResource Bool2VisibilityConverter}}"
Grid.Column="1" Grid.Row="1" Content="Down"></RepeatButton>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="RepeatButtonTransparent" TargetType="{x:Type RepeatButton}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Rectangle Fill="{TemplateBinding Background}" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarButton" TargetType="{x:Type RepeatButton}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border x:Name="border" Background="#22ffffff" BorderBrush="#22ffffff" BorderThickness="1" SnapsToDevicePixels="true">
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.7"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarThumbVertical" TargetType="{x:Type Thumb}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Rectangle x:Name="rectangle" Opacity="0.4" Height="{TemplateBinding Height}" SnapsToDevicePixels="True" Width="{TemplateBinding Width}">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#ff9a9a9a" Offset="0"></GradientStop>
<GradientStop Color="#ff6b6b6b" Offset="1"></GradientStop>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="rectangle" Property="Opacity" Value="1"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarThumbHorizontal" TargetType="{x:Type Thumb}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Rectangle x:Name="rectangle" Opacity="0.4" Height="{TemplateBinding Height}" SnapsToDevicePixels="True" Width="{TemplateBinding Width}">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Color="#ff9a9a9a" Offset="0"></GradientStop>
<GradientStop Color="#ff6b6b6b" Offset="1"></GradientStop>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="rectangle" Property="Opacity" Value="1"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="ScrollBarTemplate_Default_Vertical" TargetType="{x:Type ScrollBar}">
<Grid x:Name="Bg" SnapsToDevicePixels="true">
<Grid.RowDefinitions>
<RowDefinition MaxHeight="{DynamicResource {x:Static SystemParameters.VerticalScrollBarButtonHeightKey}}"/>
<RowDefinition Height="0.00001*"/>
<RowDefinition MaxHeight="{DynamicResource {x:Static SystemParameters.VerticalScrollBarButtonHeightKey}}"/>
</Grid.RowDefinitions>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Grid.Row="1"/>
<RepeatButton x:Name="PART_LineUpButton" Command="{x:Static ScrollBar.LineUpCommand}" IsEnabled="{TemplateBinding IsMouseOver}" Style="{StaticResource ScrollBarButton}">
<Path x:Name="ArrowTop" Data="M 0,4 C0,4 0,6 0,6 0,6 3.5,2.5 3.5,2.5 3.5,2.5 7,6 7,6 7,6 7,4 7,4 7,4 3.5,0.5 3.5,0.5 3.5,0.5 0,4 0,4 z" Fill="White" Margin="3,4,3,3" Stretch="Uniform"/>
</RepeatButton>
<Track x:Name="PART_Track" IsDirectionReversed="true" IsEnabled="{TemplateBinding IsMouseOver}" Grid.Row="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageUpCommand}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageDownCommand}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumbVertical}"/>
</Track.Thumb>
</Track>
<RepeatButton x:Name="PART_LineDownButton" Command="{x:Static ScrollBar.LineDownCommand}" IsEnabled="{TemplateBinding IsMouseOver}" Grid.Row="2" Style="{StaticResource ScrollBarButton}">
<Path x:Name="ArrowBottom" Data="M 0,2.5 C0,2.5 0,0.5 0,0.5 0,0.5 3.5,4 3.5,4 3.5,4 7,0.5 7,0.5 7,0.5 7,2.5 7,2.5 7,2.5 3.5,6 3.5,6 3.5,6 0,2.5 0,2.5 z" Fill="White" Margin="3,4,3,3" Stretch="Uniform"/>
</RepeatButton>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.7"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ScrollBarTemplate_Default_Horizontal" TargetType="{x:Type ScrollBar}">
<Grid x:Name="Bg" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarButtonWidthKey}}"/>
<ColumnDefinition Width="0.00001*"/>
<ColumnDefinition MaxWidth="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarButtonWidthKey}}"/>
</Grid.ColumnDefinitions>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Grid.Column="1"/>
<RepeatButton x:Name="PART_LineLeftButton" Command="{x:Static ScrollBar.LineLeftCommand}" IsEnabled="{TemplateBinding IsMouseOver}" Style="{StaticResource ScrollBarButton}">
<Path x:Name="ArrowLeft" Data="M 3.18,7 C3.18,7 5,7 5,7 5,7 1.81,3.5 1.81,3.5 1.81,3.5 5,0 5,0 5,0 3.18,0 3.18,0 3.18,0 0,3.5 0,3.5 0,3.5 3.18,7 3.18,7 z" Fill="White" Margin="3" Stretch="Uniform"/>
</RepeatButton>
<Track x:Name="PART_Track" Grid.Column="1" IsEnabled="{TemplateBinding IsMouseOver}">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageLeftCommand}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageRightCommand}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumbHorizontal}"/>
</Track.Thumb>
</Track>
<RepeatButton x:Name="PART_LineRightButton" Command="{x:Static ScrollBar.LineRightCommand}" Grid.Column="2" IsEnabled="{TemplateBinding IsMouseOver}" Style="{StaticResource ScrollBarButton}">
<Path x:Name="ArrowRight" Data="M 1.81,7 C1.81,7 0,7 0,7 0,7 3.18,3.5 3.18,3.5 3.18,3.5 0,0 0,0 0,0 1.81,0 1.81,0 1.81,0 5,3.5 5,3.5 5,3.5 1.81,7 1.81,7 z" Fill="White" Margin="3" Stretch="Uniform"/>
</RepeatButton>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.7"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="false"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="#ff313139"/>
<Setter Property="Foreground" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1,0"/>
<Setter Property="Width" Value="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"/>
<Setter Property="MinWidth" Value="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"/>
<Setter Property="Template" Value="{StaticResource ScrollBarTemplate_Default_Vertical}"></Setter>
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="Width" Value="Auto"/>
<Setter Property="MinWidth" Value="0"/>
<Setter Property="Height" Value="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarHeightKey}}"/>
<Setter Property="MinHeight" Value="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarHeightKey}}"/>
<Setter Property="BorderThickness" Value="0,1"/>
<Setter Property="Template" Value="{StaticResource ScrollBarTemplate_Default_Horizontal}"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
\ No newline at end of file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TextBox_None" TargetType="{x:Type TextBox}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</ResourceDictionary>
<?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>{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}</ProjectGuid>
<OutputType>library</OutputType>
<RootNamespace>VIZ.Framework.Common.Resource</RootNamespace>
<AssemblyName>VIZ.Framework.Common.Resource</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<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>
<Page Include="Style\Button\Button_MessageBox.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Style\Button\Button_WindowTop.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Style\ListBox\ListBox_None.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Style\NumberBox\NumberBox.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Style\ScrollView\ScrollView_Default.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Style\TextBox\TextBox_None.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</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="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Resource Include="Icons\delay_32x32.png" />
</ItemGroup>
<ItemGroup>
<Folder Include="Images\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Resource Include="Icons\triangle_up_16x16.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Icons\triangle_down_16x16.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Icons\setting_32x32.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
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;
using VIZ.Framework.Core;
namespace VIZ.Framework.Common
{
/// <summary>
/// 消息框
/// </summary>
[TemplatePart(Name = nameof(PART_YesButton), Type = typeof(Button))]
[TemplatePart(Name = nameof(PART_CancelButton), Type = typeof(Button))]
public class MessageBoxEx : ContentControl
{
static MessageBoxEx()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MessageBoxEx), new FrameworkPropertyMetadata(typeof(MessageBoxEx)));
}
#region PART
/// <summary>
/// 确定按钮
/// </summary>
private Button PART_YesButton;
/// <summary>
/// 取消按钮
/// </summary>
private Button PART_CancelButton;
#endregion
#region Buttons -- 按钮组合
/// <summary>
/// 按钮组合
/// </summary>
public MessageBoxExButtons Buttons
{
get { return (MessageBoxExButtons)GetValue(ButtonsProperty); }
set { SetValue(ButtonsProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Buttons. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty ButtonsProperty =
DependencyProperty.Register("Buttons", typeof(MessageBoxExButtons), typeof(MessageBoxEx), new PropertyMetadata(MessageBoxExButtons.YES));
#endregion
#region Title -- 标题
/// <summary>
/// 标题
/// </summary>
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(MessageBoxEx), new PropertyMetadata(null));
#endregion
#region Message -- 消息
/// <summary>
/// 消息
/// </summary>
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Message. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(MessageBoxEx), new PropertyMetadata(null));
#endregion
#region Result -- 返回值
/// <summary>
/// 返回值
/// </summary>
public MessageBoxExResult Result
{
get { return (MessageBoxExResult)GetValue(ResultProperty); }
set { SetValue(ResultProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Result. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty ResultProperty =
DependencyProperty.Register("Result", typeof(MessageBoxExResult), typeof(MessageBoxEx), new PropertyMetadata(MessageBoxExResult.YES));
#endregion
/// <summary>
/// 创建模板时触发
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.PART_YesButton = this.Template.FindName(nameof(PART_YesButton), this) as Button;
this.PART_CancelButton = this.Template.FindName(nameof(PART_CancelButton), this) as Button;
if (this.PART_YesButton != null)
{
this.PART_YesButton.Click -= PART_YesButton_Click;
this.PART_YesButton.Click += PART_YesButton_Click;
}
if (this.PART_CancelButton != null)
{
this.PART_CancelButton.Click -= PART_CancelButton_Click;
this.PART_CancelButton.Click += PART_CancelButton_Click;
}
}
/// <summary>
/// 点击取消按钮
/// </summary>
private void PART_CancelButton_Click(object sender, RoutedEventArgs e)
{
this.Result = MessageBoxExResult.CANCEL;
Window window = WPFHelper.GetAncestorByType<Window>(this);
window?.Close();
}
/// <summary>
/// 点击确定按钮
/// </summary>
private void PART_YesButton_Click(object sender, RoutedEventArgs e)
{
this.Result = MessageBoxExResult.YES;
Window window = WPFHelper.GetAncestorByType<Window>(this);
window?.Close();
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="title">标题</param>
/// <param name="message">消息</param>
/// <param name="buttons">按钮组</param>
/// <param name="ownerWindow">所属窗口</param>
/// <returns>返回值</returns>
public static MessageBoxExResult ShowDialog(string title, string message, MessageBoxExButtons buttons, Window ownerWindow)
{
MessageBoxExResult result = MessageBoxExResult.YES;
WPFHelper.Invoke(() =>
{
MessageBoxExWindow window = new MessageBoxExWindow();
window.box.Title = title;
window.box.Message = message;
window.box.Buttons = buttons;
window.Owner = ownerWindow;
window.ShowDialog();
result = window.box.Result;
});
return result;
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="title">标题</param>
/// <param name="message">消息</param>
/// <param name="buttons">按钮组</param>
/// <returns>返回值</returns>
public static MessageBoxExResult ShowDialog(string title, string message, MessageBoxExButtons buttons)
{
MessageBoxExResult result = MessageBoxExResult.YES;
WPFHelper.Invoke(() =>
{
MessageBoxExWindow window = new MessageBoxExWindow();
window.box.Title = title;
window.box.Message = message;
window.box.Buttons = buttons;
window.Owner = Application.Current?.MainWindow;
window.ShowDialog();
result = window.box.Result;
});
return result;
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="title">标题</param>
/// <param name="message">消息</param>
/// <returns>返回值</returns>
public static MessageBoxExResult ShowDialog(string title, string message)
{
return ShowDialog(title, message, MessageBoxExButtons.YES);
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="message">消息</param>
/// <returns>返回值</returns>
public static MessageBoxExResult ShowDialog(string message)
{
return ShowDialog("提示", message);
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="message">消息</param>
/// <param name="ownerWindow">所属窗口</param>
/// <returns>返回值</returns>
public static MessageBoxExResult ShowDialog(string message, Window ownerWindow)
{
return ShowDialog("提示", message, MessageBoxExButtons.YES, ownerWindow);
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="clr-namespace:VIZ.Framework.Common">
<Style x:Key="VMessageBox_Button_Yes" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="140"></Setter>
<Setter Property="Height" Value="45"></Setter>
<Setter Property="Margin" Value="10,0,10,0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" CornerRadius="10" Background="#aa007cff">
<TextBlock Text="确定" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="18" Foreground="White"></TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#ff007cff"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="VMessageBox_Button_Cancel" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="140"></Setter>
<Setter Property="Height" Value="45"></Setter>
<Setter Property="Margin" Value="10,0,10,0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" CornerRadius="10" Background="#aadcdcdc">
<TextBlock Text="取消" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="18" Foreground="Black"></TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#ffdcdcdc"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="common:MessageBoxEx">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="400"></Setter>
<Setter Property="Height" Value="300"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="common:MessageBoxEx">
<Border Background="White" BorderBrush="#22000000" BorderThickness="1" CornerRadius="40">
<Border.Effect>
<DropShadowEffect Opacity="0.36"/>
</Border.Effect>
<Grid Margin="30,20,30,20">
<Grid.RowDefinitions>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="80"></RowDefinition>
</Grid.RowDefinitions>
<common:DragWindowBar Grid.RowSpan="3" Background="Transparent"></common:DragWindowBar>
<TextBlock Text="{TemplateBinding Title}" Foreground="Black" FontSize="40" VerticalAlignment="Center" HorizontalAlignment="Left"
FontWeight="Black"></TextBlock>
<TextBlock Grid.Row="1" Text="{TemplateBinding Message}" Foreground="Black" FontSize="24" TextWrapping="Wrap" TextTrimming="CharacterEllipsis"></TextBlock>
<StackPanel Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Horizontal">
<Button x:Name="PART_CancelButton" Grid.Row="2" Style="{StaticResource VMessageBox_Button_Cancel}" Content="取消" Visibility="Hidden"></Button>
<Button x:Name="PART_YesButton" Grid.Row="2" Style="{StaticResource VMessageBox_Button_Yes}" Content="确定"></Button>
</StackPanel>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Buttons" Value="YES_CANCEL">
<Setter TargetName="PART_CancelButton" Property="Visibility" Value="Visible"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 消息框按钮组
/// </summary>
public enum MessageBoxExButtons
{
/// <summary>
/// 确定
/// </summary>
YES,
/// <summary>
/// 确定 & 取消
/// </summary>
YES_CANCEL
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 消息框返回
/// </summary>
public enum MessageBoxExResult
{
/// <summary>
/// 确定
/// </summary>
YES,
/// <summary>
/// <summary>
/// 取消
/// </summary>
CANCEL
}
}
<Window x:Class="VIZ.Framework.Common.MessageBoxExWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:VIZ.Framework.Common"
mc:Ignorable="d" WindowStartupLocation="CenterScreen" WindowState="Normal" WindowStyle="None" AllowsTransparency="True"
Title="VMessageBoxWindow" Height="400" Width="600" Background="Transparent">
<local:MessageBoxEx x:Name="box" Width="580" Height="380"></local:MessageBoxEx>
</Window>
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.Shapes;
namespace VIZ.Framework.Common
{
/// <summary>
/// MessageBoxExWindow.xaml 的交互逻辑
/// </summary>
public partial class MessageBoxExWindow : Window
{
public MessageBoxExWindow()
{
InitializeComponent();
}
}
}
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("VIZ.Framework.Common")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.Common")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace VIZ.Framework.Common.Properties {
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[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>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </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("VIZ.Framework.Common.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
<?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>
\ No newline at end of file
//------------------------------------------------------------------------------
// <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 VIZ.Framework.Common.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.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;
}
}
}
}
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
\ No newline at end of file
using System;
namespace VIZ.Framework.Common
{
public static class Disposer
{
public static void SafeDispose<T>(ref T resource) where T : class
{
if (resource == null)
{
return;
}
var disposer = resource as IDisposable;
if (disposer != null)
{
try
{
disposer.Dispose();
}
catch
{
}
}
resource = null;
}
}
}
using System;
using System.Runtime.InteropServices;
namespace VIZ.Framework.Common
{
public static class NativeMethods
{
[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetDesktopWindow();
}
}
using SharpDX.Direct2D1;
using System;
using System.Collections.Generic;
namespace VIZ.Framework.Common
{
public class ResourceCache
{
// - field -----------------------------------------------------------------------
private Dictionary<string, Func<RenderTarget, object>> generators = new Dictionary<string, Func<RenderTarget, object>>();
private Dictionary<string, object> resources = new Dictionary<string, object>();
private RenderTarget renderTarget = null;
// - property --------------------------------------------------------------------
public RenderTarget RenderTarget
{
get { return renderTarget; }
set { renderTarget = value; UpdateResources(); }
}
public int Count
{
get { return resources.Count; }
}
public object this[string key]
{
get { return resources[key]; }
}
public Dictionary<string, object>.KeyCollection Keys
{
get { return resources.Keys; }
}
public Dictionary<string, object>.ValueCollection Values
{
get { return resources.Values; }
}
// - public methods --------------------------------------------------------------
public void Add(string key, Func<RenderTarget, object> gen)
{
object resOld;
if (resources.TryGetValue(key, out resOld))
{
Disposer.SafeDispose(ref resOld);
generators.Remove(key);
resources.Remove(key);
}
if (renderTarget == null)
{
generators.Add(key, gen);
resources.Add(key, null);
}
else
{
var res = gen(renderTarget);
generators.Add(key, gen);
resources.Add(key, res);
}
}
public void Clear()
{
foreach (var key in resources.Keys)
{
var res = resources[key];
Disposer.SafeDispose(ref res);
}
generators.Clear();
resources.Clear();
}
public bool ContainsKey(string key)
{
return resources.ContainsKey(key);
}
public bool ContainsValue(object val)
{
return resources.ContainsValue(val);
}
public Dictionary<string, object>.Enumerator GetEnumerator()
{
return resources.GetEnumerator();
}
public bool Remove(string key)
{
object res;
if (resources.TryGetValue(key, out res))
{
Disposer.SafeDispose(ref res);
generators.Remove(key);
resources.Remove(key);
return true;
}
else
{
return false;
}
}
public bool TryGetValue(string key, out object res)
{
return resources.TryGetValue(key, out res);
}
// - private methods -------------------------------------------------------------
private void UpdateResources()
{
if (renderTarget == null) { return; }
foreach (var g in generators)
{
var key = g.Key;
var gen = g.Value;
var res = gen(renderTarget);
object resOld;
if (resources.TryGetValue(key, out resOld))
{
Disposer.SafeDispose(ref resOld);
resources.Remove(key);
}
resources.Add(key, res);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 图片渲染格式
/// </summary>
public enum WicBitmapFormat
{
/// <summary>
/// jpg格式
/// </summary>
JPG
}
}
using SharpDX.WIC;
using SharpDX.Direct2D1;
using SharpDX.DXGI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
using System.IO;
using SharpDX.IO;
namespace VIZ.Framework.Common
{
/// <summary>
/// WIC图片辅助类
/// </summary>
public static class WicBitmapHelper
{
/// <summary>
/// 渲染至WicBitmap
/// </summary>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <param name="render">渲染方法</param>
/// <param name="plugins">渲染插件</param>
/// <returns>WicBitmap</returns>
public static SharpDX.WIC.Bitmap RenderToBitmap(int width, int height, Action<VideoRenderContext> render, List<string> plugins = null)
{
ImagingFactory wicFactory = new ImagingFactory();
SharpDX.Direct2D1.Factory d2dFactory = new SharpDX.Direct2D1.Factory();
SharpDX.WIC.Bitmap wicBitmap = new SharpDX.WIC.Bitmap(wicFactory, width, height, SharpDX.WIC.PixelFormat.Format32bppBGR, BitmapCreateCacheOption.CacheOnLoad);
RenderTargetProperties renderTargetProperties = new RenderTargetProperties(RenderTargetType.Default, new SharpDX.Direct2D1.PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Unknown), 0, 0, RenderTargetUsage.None, FeatureLevel.Level_DEFAULT);
WicRenderTarget d2dRenderTarget = new WicRenderTarget(d2dFactory, wicBitmap, renderTargetProperties);
d2dRenderTarget.BeginDraw();
VideoRenderContext context = new VideoRenderContext();
context.Mode = VideoRenderMode.Image;
context.Target = d2dRenderTarget;
context.RenderImagePlugins = plugins;
render.Invoke(context);
d2dRenderTarget.EndDraw();
d2dRenderTarget.Dispose();
d2dFactory.Dispose();
wicFactory.Dispose();
return wicBitmap;
}
/// <summary>
/// 渲染至文件
/// </summary>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <param name="fileName">文件名</param>
/// <param name="format">图片格式</param>
/// <param name="render">渲染行为</param>
public static void RenderToFile(int width, int height, string fileName, WicBitmapFormat format, Action<WicRenderTarget> render)
{
ImagingFactory wicFactory = new ImagingFactory();
SharpDX.Direct2D1.Factory d2dFactory = new SharpDX.Direct2D1.Factory();
SharpDX.WIC.Bitmap wicBitmap = new SharpDX.WIC.Bitmap(wicFactory, width, height, SharpDX.WIC.PixelFormat.Format32bppBGR, BitmapCreateCacheOption.CacheOnLoad);
RenderTargetProperties renderTargetProperties = new RenderTargetProperties(RenderTargetType.Default, new SharpDX.Direct2D1.PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Unknown), 0, 0, RenderTargetUsage.None, FeatureLevel.Level_DEFAULT);
WicRenderTarget d2dRenderTarget = new WicRenderTarget(d2dFactory, wicBitmap, renderTargetProperties);
d2dRenderTarget.BeginDraw();
render.Invoke(d2dRenderTarget);
d2dRenderTarget.EndDraw();
if (File.Exists(fileName))
{
File.Delete(fileName);
}
WICStream stream = new WICStream(wicFactory, fileName, NativeFileAccess.Write);
BitmapEncoder encoder = GetBitmapFrameEncoder(wicFactory, format);
encoder.Initialize(stream);
// Create a Frame encoder
BitmapFrameEncode bitmapFrameEncode = new BitmapFrameEncode(encoder);
bitmapFrameEncode.Initialize();
bitmapFrameEncode.SetSize(width, height);
var pixelFormatGuid = SharpDX.WIC.PixelFormat.FormatDontCare;
bitmapFrameEncode.SetPixelFormat(ref pixelFormatGuid);
bitmapFrameEncode.WriteSource(wicBitmap);
bitmapFrameEncode.Commit();
encoder.Commit();
bitmapFrameEncode.Dispose();
encoder.Dispose();
stream.Dispose();
d2dRenderTarget.Dispose();
wicBitmap.Dispose();
d2dFactory.Dispose();
wicFactory.Dispose();
}
/// <summary>
/// 获取保存图片格式
/// </summary>
/// <param name="factory">图片工厂</param>
/// <param name="format">图片格式</param>
/// <returns>图片格式</returns>
private static BitmapEncoder GetBitmapFrameEncoder(ImagingFactory factory, WicBitmapFormat format)
{
switch (format)
{
case WicBitmapFormat.JPG:
return new JpegBitmapEncoder(factory);
default:
return null;
}
}
}
}
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
namespace VIZ.Framework.Common
{
public abstract class D2dControl : System.Windows.Controls.Image
{
// - field -----------------------------------------------------------------------
private SharpDX.Direct3D11.Device device;
private Texture2D renderTarget;
private Dx11ImageSource d3DSurface;
private RenderTarget d2DRenderTarget;
private SharpDX.Direct2D1.Factory d2DFactory;
private readonly Stopwatch renderTimer = new Stopwatch();
protected ResourceCache resCache = new ResourceCache();
private long lastFrameTime = 0;
private long lastRenderTime = 0;
private int frameCount = 0;
private int frameCountHistTotal = 0;
private Queue<int> frameCountHist = new Queue<int>();
// - property --------------------------------------------------------------------
public static bool IsInDesignMode
{
get
{
var prop = DesignerProperties.IsInDesignModeProperty;
var isDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(prop, typeof(FrameworkElement)).Metadata.DefaultValue;
return isDesignMode;
}
}
private static readonly DependencyPropertyKey FpsPropertyKey = DependencyProperty.RegisterReadOnly(
"Fps",
typeof(int),
typeof(D2dControl),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.None)
);
public static readonly DependencyProperty FpsProperty = FpsPropertyKey.DependencyProperty;
public int Fps
{
get { return (int)GetValue(FpsProperty); }
protected set { SetValue(FpsPropertyKey, value); }
}
public static DependencyProperty RenderWaitProperty = DependencyProperty.Register(
"RenderWait",
typeof(int),
typeof(D2dControl),
new FrameworkPropertyMetadata(2, OnRenderWaitChanged)
);
public int RenderWait
{
get { return (int)GetValue(RenderWaitProperty); }
set { SetValue(RenderWaitProperty, value); }
}
// - public methods --------------------------------------------------------------
public D2dControl()
{
base.Loaded += Window_Loaded;
base.Unloaded += Window_Closing;
base.Stretch = System.Windows.Media.Stretch.Fill;
}
public abstract void Render(RenderTarget target);
// - event handler ---------------------------------------------------------------
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (D2dControl.IsInDesignMode)
{
return;
}
StartD3D();
StartRendering();
}
private void Window_Closing(object sender, RoutedEventArgs e)
{
if (D2dControl.IsInDesignMode)
{
return;
}
StopRendering();
EndD3D();
}
private void OnRendering(object sender, EventArgs e)
{
if (!renderTimer.IsRunning)
{
return;
}
PrepareAndCallRender();
d3DSurface.InvalidateD3DImage();
lastRenderTime = renderTimer.ElapsedMilliseconds;
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
CreateAndBindTargets();
base.OnRenderSizeChanged(sizeInfo);
}
private void OnIsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (d3DSurface.IsFrontBufferAvailable)
{
StartRendering();
this.CreateAndBindTargets();
}
else
{
StopRendering();
}
}
private static void OnRenderWaitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (D2dControl)d;
control.d3DSurface.RenderWait = (int)e.NewValue;
}
// - private methods -------------------------------------------------------------
private void StartD3D()
{
device = new SharpDX.Direct3D11.Device(DriverType.Hardware, DeviceCreationFlags.BgraSupport);
d3DSurface = new Dx11ImageSource();
d3DSurface.IsFrontBufferAvailableChanged += OnIsFrontBufferAvailableChanged;
CreateAndBindTargets();
base.Source = d3DSurface;
}
private void EndD3D()
{
d3DSurface.IsFrontBufferAvailableChanged -= OnIsFrontBufferAvailableChanged;
base.Source = null;
Disposer.SafeDispose(ref d2DRenderTarget);
Disposer.SafeDispose(ref d2DFactory);
Disposer.SafeDispose(ref d3DSurface);
Disposer.SafeDispose(ref renderTarget);
Disposer.SafeDispose(ref device);
}
private void CreateAndBindTargets()
{
if (d3DSurface == null)
{
return;
}
d3DSurface.SetRenderTarget(null);
Disposer.SafeDispose(ref d2DRenderTarget);
Disposer.SafeDispose(ref d2DFactory);
Disposer.SafeDispose(ref renderTarget);
var width = Math.Max((int)ActualWidth, 100);
var height = Math.Max((int)ActualHeight, 100);
var renderDesc = new Texture2DDescription
{
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
Format = Format.B8G8R8A8_UNorm,
Width = width,
Height = height,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
OptionFlags = ResourceOptionFlags.Shared,
CpuAccessFlags = CpuAccessFlags.None,
ArraySize = 1
};
renderTarget = new Texture2D(device, renderDesc);
var surface = renderTarget.QueryInterface<Surface>();
d2DFactory = new SharpDX.Direct2D1.Factory();
var rtp = new RenderTargetProperties(new PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied));
d2DRenderTarget = new RenderTarget(d2DFactory, surface, rtp);
resCache.RenderTarget = d2DRenderTarget;
d3DSurface.SetRenderTarget(renderTarget);
device.ImmediateContext.Rasterizer.SetViewport(0, 0, width, height, 0.0f, 1.0f);
}
private void StartRendering()
{
if (renderTimer.IsRunning)
{
return;
}
System.Windows.Media.CompositionTarget.Rendering -= OnRendering;
System.Windows.Media.CompositionTarget.Rendering += OnRendering;
renderTimer.Start();
}
private void StopRendering()
{
if (!renderTimer.IsRunning)
{
return;
}
System.Windows.Media.CompositionTarget.Rendering -= OnRendering;
renderTimer.Stop();
}
private void PrepareAndCallRender()
{
if (device == null)
{
return;
}
d2DRenderTarget.BeginDraw();
Render(d2DRenderTarget);
d2DRenderTarget.EndDraw();
CalcFps();
device.ImmediateContext.Flush();
}
private void CalcFps()
{
frameCount++;
if (renderTimer.ElapsedMilliseconds - lastFrameTime > 1000)
{
frameCountHist.Enqueue(frameCount);
frameCountHistTotal += frameCount;
if (frameCountHist.Count > 5)
{
frameCountHistTotal -= frameCountHist.Dequeue();
}
Fps = frameCountHistTotal / frameCountHist.Count;
frameCount = 0;
lastFrameTime = renderTimer.ElapsedMilliseconds;
}
}
}
}
using SharpDX.Direct3D9;
using System;
using System.Threading;
using System.Windows.Interop;
using VIZ.Framework.Core;
using VIZ.Framework.Storage;
using VIZ.Framework.Domain;
namespace VIZ.Framework.Common
{
public class Dx11ImageSource : D3DImage, IDisposable
{
// - field -----------------------------------------------------------------------
private static int ActiveClients;
private static Direct3DEx D3DContext;
private static DeviceEx D3DDevice;
private Texture renderTarget;
// - property --------------------------------------------------------------------
public int RenderWait { get; set; } = 5; // default: 5ms
// - public methods --------------------------------------------------------------
public Dx11ImageSource()
{
this.RenderWait = ApplicationDomain.IniStorage.GetValue<VideoConfig, int>(p => p.VIDEO_RENDER_WAIT);
StartD3D();
Dx11ImageSource.ActiveClients++;
}
public void Dispose()
{
SetRenderTarget(null);
Disposer.SafeDispose(ref renderTarget);
Dx11ImageSource.ActiveClients--;
EndD3D();
}
public void InvalidateD3DImage()
{
if (renderTarget != null)
{
base.Lock();
if (RenderWait != 0)
{
Thread.Sleep(RenderWait);
}
base.AddDirtyRect(new System.Windows.Int32Rect(0, 0, base.PixelWidth, base.PixelHeight));
base.Unlock();
}
}
public void SetRenderTarget(SharpDX.Direct3D11.Texture2D target)
{
if (renderTarget != null)
{
renderTarget = null;
base.Lock();
base.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
base.Unlock();
}
if (target == null)
{
return;
}
var format = Dx11ImageSource.TranslateFormat(target);
var handle = GetSharedHandle(target);
if (!IsShareable(target))
{
throw new ArgumentException("Texture must be created with ResouceOptionFlags.Shared");
}
if (format == Format.Unknown)
{
throw new ArgumentException("Texture format is not compatible with OpenSharedResouce");
}
if (handle == IntPtr.Zero)
{
throw new ArgumentException("Invalid handle");
}
renderTarget = new Texture(Dx11ImageSource.D3DDevice, target.Description.Width, target.Description.Height, 1, Usage.RenderTarget, format, Pool.Default, ref handle);
using (var surface = renderTarget.GetSurfaceLevel(0))
{
base.Lock();
base.SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface.NativePointer);
base.Unlock();
}
}
// - private methods -------------------------------------------------------------
private void StartD3D()
{
if (Dx11ImageSource.ActiveClients != 0)
{
return;
}
var presentParams = GetPresentParameters();
var createFlags = CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve;
Dx11ImageSource.D3DContext = new Direct3DEx();
Dx11ImageSource.D3DDevice = new DeviceEx(D3DContext, 0, DeviceType.Hardware, IntPtr.Zero, createFlags, presentParams);
}
private void EndD3D()
{
if (Dx11ImageSource.ActiveClients != 0)
{
return;
}
Disposer.SafeDispose(ref renderTarget);
Disposer.SafeDispose(ref Dx11ImageSource.D3DDevice);
Disposer.SafeDispose(ref Dx11ImageSource.D3DContext);
}
private static void ResetD3D()
{
if (Dx11ImageSource.ActiveClients == 0)
{
return;
}
var presentParams = GetPresentParameters();
Dx11ImageSource.D3DDevice.ResetEx(ref presentParams);
}
private static PresentParameters GetPresentParameters()
{
var presentParams = new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.DeviceWindowHandle = NativeMethods.GetDesktopWindow();
presentParams.PresentationInterval = PresentInterval.Default;
return presentParams;
}
private IntPtr GetSharedHandle(SharpDX.Direct3D11.Texture2D texture)
{
using (var resource = texture.QueryInterface<SharpDX.DXGI.Resource>())
{
return resource.SharedHandle;
}
}
private static Format TranslateFormat(SharpDX.Direct3D11.Texture2D texture)
{
switch (texture.Description.Format)
{
case SharpDX.DXGI.Format.R10G10B10A2_UNorm: return SharpDX.Direct3D9.Format.A2B10G10R10;
case SharpDX.DXGI.Format.R16G16B16A16_Float: return SharpDX.Direct3D9.Format.A16B16G16R16F;
case SharpDX.DXGI.Format.B8G8R8A8_UNorm: return SharpDX.Direct3D9.Format.A8R8G8B8;
default: return SharpDX.Direct3D9.Format.Unknown;
}
}
private static bool IsShareable(SharpDX.Direct3D11.Texture2D texture)
{
return (texture.Description.OptionFlags & SharpDX.Direct3D11.ResourceOptionFlags.Shared) != 0;
}
}
}
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VIZ.Framework.Common">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/VIZ.Framework.Common;component/MessageBox/MessageBoxEx.xaml"></ResourceDictionary>
<ResourceDictionary Source="/VIZ.Framework.Common;component/Widgets/VideoTimeBar/VideoTimeBar.xaml"></ResourceDictionary>
<ResourceDictionary Source="/VIZ.Framework.Common;component/Widgets/NavigationControl/NavigationControl.xaml"></ResourceDictionary>
<ResourceDictionary Source="/VIZ.Framework.Common;component/Widgets/NumberBox/NumberBox.xaml"></ResourceDictionary>
<ResourceDictionary Source="/VIZ.Framework.Common;component/Widgets/ColorPickButton/ColorPickButton.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<?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>{92834C05-703E-4F05-9224-F36220939D8F}</ProjectGuid>
<OutputType>library</OutputType>
<RootNamespace>VIZ.Framework.Common</RootNamespace>
<AssemblyName>VIZ.Framework.Common</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=2.0.14.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.14\lib\net45\log4net.dll</HintPath>
</Reference>
<Reference Include="NDILibDotNet2">
<HintPath>..\05-Lib\NDILibDotNet2.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\OpenCvSharp4.4.6.0.20220608\lib\net48\OpenCvSharp.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Direct2D1, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Direct2D1.4.2.0\lib\net45\SharpDX.Direct2D1.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Direct3D11, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Direct3D9, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Direct3D9.4.2.0\lib\net45\SharpDX.Direct3D9.dll</HintPath>
</Reference>
<Reference Include="SharpDX.DXGI, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Mathematics, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Security" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<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>
<Page Include="MessageBox\MessageBoxEx.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="MessageBox\MessageBoxExWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="VideoControl\Control\VideoControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Widgets\ColorPickButton\ColorPickButton.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Widgets\NavigationControl\NavigationControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Widgets\NumberBox\NumberBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Widgets\VideoTimeBar\VideoTimeBar.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="MessageBox\MessageBoxEx.cs" />
<Compile Include="MessageBox\MessageBoxExButtons.cs" />
<Compile Include="MessageBox\MessageBoxExResult.cs" />
<Compile Include="MessageBox\MessageBoxExWindow.xaml.cs">
<DependentUpon>MessageBoxExWindow.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>
<Compile Include="SharpDx\Core\Disposer.cs" />
<Compile Include="SharpDx\Core\NativeMethods.cs" />
<Compile Include="SharpDx\Core\ResourceCache.cs" />
<Compile Include="SharpDx\WIC\WicBitmapFormat.cs" />
<Compile Include="SharpDx\WIC\WicBitmapHelper.cs" />
<Compile Include="SharpDx\WPF\D2dControl.cs" />
<Compile Include="SharpDx\WPF\Dx11ImageSource.cs" />
<Compile Include="VideoControl\Control\IVideoPlugin.cs" />
<Compile Include="VideoControl\Control\Plugin\ClipBox\ClipBoxExpand.cs" />
<Compile Include="VideoControl\Control\Plugin\ClipBox\ClipBoxPlugin.cs" />
<Compile Include="VideoControl\Control\Plugin\ClipBox\Info\ClipBoxInfo.cs" />
<Compile Include="VideoControl\Control\Plugin\SelectionBox\EventArgs\SelectionBoxSelectedEventArgs.cs" />
<Compile Include="VideoControl\Control\Plugin\SelectionBox\Info\SelectionBoxInfo.cs" />
<Compile Include="VideoControl\Control\Plugin\SelectionBox\SelectionBoxExpand.cs" />
<Compile Include="VideoControl\Control\Plugin\SelectionBox\SelectionBoxPlugin.cs" />
<Compile Include="VideoControl\Control\Plugin\TrackingBox\EventArgs\TrackingBoxClickEventArgs.cs" />
<Compile Include="VideoControl\Control\Plugin\TrackingBox\TrackingBoxExpand.cs" />
<Compile Include="VideoControl\Control\Plugin\TrackingBox\Info\TrackingBoxInfo.cs" />
<Compile Include="VideoControl\Control\Plugin\TrackingBox\TrackingBoxPlugin.cs" />
<Compile Include="VideoControl\Control\Plugin\VideoPluginBase.cs" />
<Compile Include="VideoControl\Control\VideoRenderContext.cs" />
<Compile Include="VideoControl\Control\VideoControl.xaml.cs">
<DependentUpon>VideoControl.xaml</DependentUpon>
</Compile>
<Compile Include="VideoControl\Control\VideoControlPluginNames.cs" />
<Compile Include="VideoControl\Control\VideoCustomRender.cs" />
<Compile Include="VideoControl\Control\VideoRenderInfo.cs" />
<Compile Include="VideoControl\Control\VideoRenderMode.cs" />
<Compile Include="VideoControl\Stream\IVideoFrame.cs" />
<Compile Include="VideoControl\Stream\IVideoStream.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIStream.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIStream.Static.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIStreamOption.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIStreamInfo.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIStreamTaskBase.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIStreamTaskNames.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIStreamVideoFrame.cs" />
<Compile Include="VideoControl\Stream\NDI\Task\NDIStreamExecuteVideoTask.cs" />
<Compile Include="VideoControl\Stream\NDI\Task\NDIStreamFindStreamTask.cs" />
<Compile Include="VideoControl\Stream\NDI\Task\NDIStreamRecvVideoTask.cs" />
<Compile Include="VideoControl\Stream\OpenCV\OpenCVPropertyInfos.cs" />
<Compile Include="VideoControl\Stream\OpenCV\OpenCVStreamTaskNames.cs" />
<Compile Include="VideoControl\Stream\OpenCV\OpenCVStream.cs" />
<Compile Include="VideoControl\Stream\OpenCV\OpenCVStreamOption.cs" />
<Compile Include="VideoControl\Stream\OpenCV\OpenCVStreamStatus.cs" />
<Compile Include="VideoControl\Stream\OpenCV\OpenCVStreamTaskBase.cs" />
<Compile Include="VideoControl\Stream\OpenCV\OpenCVStreeamVideoFrame.cs" />
<Compile Include="VideoControl\Stream\OpenCV\Task\OpenCVStreamExecuteVideoTask.cs" />
<Compile Include="VideoControl\Stream\OpenCV\Task\OpenCVStreamRecvVideoTask.cs" />
<Compile Include="VideoControl\Stream\VideoFrameBase.cs" />
<Compile Include="VideoControl\Stream\VideoFrameEventArgs.cs" />
<Compile Include="VideoControl\Stream\VideoStreamManager.cs" />
<Compile Include="VideoControl\Stream\VideoStreamBase.cs" />
<Compile Include="VideoControl\Stream\VideoStreamOptionBase.cs" />
<Compile Include="VideoControl\Stream\VideoStreamTaskBase.cs" />
<Compile Include="Widgets\ColorPickButton\ColorPickButton.cs" />
<Compile Include="Widgets\DragWindowBar\DragWindowBar.cs" />
<Compile Include="Widgets\NavigationControl\NavigationConfig.cs" />
<Compile Include="Widgets\NavigationControl\NavigationControl.cs" />
<Compile Include="Widgets\NavigationControl\NavigationItemControl.cs" />
<Compile Include="Widgets\NoneWindow\NoneWindow.cs" />
<Compile Include="Widgets\NumberBox\NumberBox.cs" />
<Compile Include="Widgets\VideoTimeBar\EventArgs\VideoTimeBarValueChangedEventArgs.cs" />
<Compile Include="Widgets\VideoTimeBar\VideoTimeBar.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="VideoControl\Widgets\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
using SharpDX.Direct2D1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频插件
/// </summary>
public interface IVideoPlugin
{
/// <summary>
/// 插件名称
/// </summary>
string Name { get; }
/// <summary>
/// 视频控件
/// </summary>
VideoControl VideoControl { get; }
/// <summary>
/// 视频渲染
/// </summary>
VideoCustomRender VideoRender { get; }
/// <summary>
/// 是否启用
/// </summary>
bool IsEnabled { get; set; }
/// <summary>
/// 附加
/// </summary>
void Attach();
/// <summary>
/// 卸载
/// </summary>
void Detach();
/// <summary>
/// 渲染
/// </summary>
/// <param name="context">渲染上下文</param>
void Render(VideoRenderContext context);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 跟踪框扩展
/// </summary>
public static class ClipBoxExpand
{
/// <summary>
/// 更新跟踪框
/// </summary>
/// <param name="videoControl">视频控件</param>
/// <param name="clipBoxInfo">裁剪框信息</param>
public static void UpdateClipBox(this VideoControl videoControl, ClipBoxInfo clipBoxInfo)
{
if (videoControl.videoRender == null)
return;
ClipBoxPlugin plugin = videoControl.GetPlugin<ClipBoxPlugin>(VideoControlPluginNames.ClipBox);
if (plugin == null)
return;
plugin.Update(clipBoxInfo);
}
/// <summary>
/// 清理跟踪框
/// </summary>
/// <param name="videoControl">视频控件</param>
public static void ClearClipBox(this VideoControl videoControl)
{
if (videoControl.videoRender == null)
return;
ClipBoxPlugin plugin = videoControl.GetPlugin<ClipBoxPlugin>(VideoControlPluginNames.ClipBox);
if (plugin == null)
return;
plugin.Update(null);
}
}
}
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VIZ.Framework.Core;
namespace VIZ.Framework.Common
{
/// <summary>
/// 裁剪框插件
/// </summary>
public class ClipBoxPlugin : VideoPluginBase
{
/// <summary>
/// 裁剪框插件
/// </summary>
/// <param name="videoControl">视频控件</param>
public ClipBoxPlugin(VideoControl videoControl) : base(videoControl)
{
}
/// <summary>
/// 名称
/// </summary>
public override string Name => VideoControlPluginNames.ClipBox;
/// <summary>
/// 跟踪框信息
/// </summary>
private volatile ClipBoxInfo clipBoxInfo;
/// <summary>
/// 更新数据
/// </summary>
/// <param name="clipBoxInfo">跟踪框信息</param>
public void Update(ClipBoxInfo clipBoxInfo)
{
this.clipBoxInfo = clipBoxInfo;
}
/// <summary>
/// 渲染
/// </summary>
/// <param name="context">渲染上下文</param>
public override void Render(VideoRenderContext context)
{
// 画面渲染区域
ClipBoxInfo info = this.clipBoxInfo;
if (info == null)
return;
float half = info.DrawingBorderWidth / 2f;
RawRectangleF drawRect;
RawRectangleF fillRect;
if (context.Mode == VideoRenderMode.UI)
{
drawRect = ImageHelper.ConvertImageRectToUiRect(context.VideoRenderInfo.Frame.Width, context.VideoRenderInfo.Frame.Height, context.VideoRenderInfo.DrawingRect, info.SrcRect.ToRect()).ToRawRectangleF();
fillRect = context.VideoRenderInfo.ControlRect.ToRawRectangleF();
}
else
{
drawRect = info.SrcRect;
fillRect = new RawRectangleF(0, 0, context.VideoRenderInfo.Frame.Width, context.VideoRenderInfo.Frame.Height);
}
drawRect = new RawRectangleF(drawRect.Left + half, drawRect.Top + half, drawRect.Right - half, drawRect.Bottom - half);
List<RawRectangleF> maskList = new List<RawRectangleF>();
// left
if (drawRect.Left > context.VideoRenderInfo.DrawingRect.Left + half)
{
maskList.Add(new RawRectangleF(
(float)context.VideoRenderInfo.DrawingRect.Left, (float)context.VideoRenderInfo.DrawingRect.Top,
drawRect.Left - half, (float)context.VideoRenderInfo.DrawingRect.Bottom));
}
// right
if (drawRect.Right < fillRect.Right - half)
{
maskList.Add(new RawRectangleF(
drawRect.Right + half, (float)context.VideoRenderInfo.DrawingRect.Top,
(float)context.VideoRenderInfo.DrawingRect.Right, (float)context.VideoRenderInfo.DrawingRect.Bottom));
}
// top
if (drawRect.Top > half)
{
maskList.Add(new RawRectangleF(
drawRect.Left - half, (float)context.VideoRenderInfo.DrawingRect.Top,
drawRect.Right + half, drawRect.Top - half));
}
// bottom
if (drawRect.Bottom < fillRect.Bottom - half)
{
maskList.Add(new RawRectangleF(
drawRect.Left - half, drawRect.Bottom + half,
drawRect.Right + half, (float)context.VideoRenderInfo.DrawingRect.Bottom));
}
// 绘制
SolidColorBrush maskBrush = new SolidColorBrush(context.Target, info.MaskColor);
foreach (RawRectangleF mask in maskList)
{
context.Target.FillRectangle(mask, maskBrush);
}
SolidColorBrush brush = new SolidColorBrush(context.Target, info.DrawingBorderColor);
context.Target.DrawRectangle(drawRect, brush, info.DrawingBorderWidth);
}
}
}
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 裁剪框信息
/// </summary>
public class ClipBoxInfo
{
/// <summary>
/// 源区域
/// </summary>
public RawRectangleF SrcRect { get; set; }
/// <summary>
/// 绘制边框颜色
/// </summary>
public RawColor4 DrawingBorderColor { get; set; }
/// <summary>
/// 绘制边框宽度
/// </summary>
public float DrawingBorderWidth { get; set; }
/// <summary>
/// 遮罩颜色
/// </summary>
public RawColor4 MaskColor { get; set; }
}
}
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 框选框选择事件参数
/// </summary>
public class SelectionBoxSelectedEventArgs : EventArgs
{
/// <summary>
/// 绘制区域
/// </summary>
public RawRectangleF DrawingRect { get; set; }
/// <summary>
/// 源区域
/// </summary>
public RawRectangleF SrcRect { get; set; }
}
}
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace VIZ.Framework.Common
{
/// <summary>
/// 框选框信息
/// </summary>
public class SelectionBoxInfo
{
/// <summary>
/// 绘制区域
/// </summary>
public RawRectangleF DrawingRect { get; set; }
/// <summary>
/// 绘制边框颜色
/// </summary>
public RawColor4 DrawingBorderColor { get; set; }
/// <summary>
/// 绘制边框宽度
/// </summary>
public float DrawingBorderWidth { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 框选框插件扩展
/// </summary>
public static class SelectionBoxExpand
{
/// <summary>
/// 更新框选框
/// </summary>
/// <param name="videoControl">视频控件</param>
/// <param name="selectionBoxInfo">框选框信息</param>
public static void UpdateSelectionBox(this VideoControl videoControl, SelectionBoxInfo selectionBoxInfo)
{
if (videoControl.videoRender == null)
return;
SelectionBoxPlugin plugin = videoControl.GetPlugin<SelectionBoxPlugin>(VideoControlPluginNames.SelectionBox);
if (plugin == null)
return;
plugin.Update(selectionBoxInfo);
}
/// <summary>
/// 清理框选框
/// </summary>
/// <param name="videoControl">视频控件</param>
public static void ClearSelectionBox(this VideoControl videoControl)
{
if (videoControl.videoRender == null)
return;
SelectionBoxPlugin plugin = videoControl.GetPlugin<SelectionBoxPlugin>(VideoControlPluginNames.SelectionBox);
if (plugin == null)
return;
plugin.Update(null);
}
}
}
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VIZ.Framework.Core;
using VIZ.Framework.Storage;
using VIZ.Framework.Domain;
namespace VIZ.Framework.Common
{
/// <summary>
/// 框选框插件
/// </summary>
public class SelectionBoxPlugin : VideoPluginBase
{
/// <summary>
/// 框选框插件
/// </summary>
/// <param name="videoControl">视频控件</param>
public SelectionBoxPlugin(VideoControl videoControl) : base(videoControl)
{
this.drawingWidth = ApplicationDomain.IniStorage.GetValue<VideoConfig, int>(p => p.VIDEO_SELECTION_BOX_BORDER_WIDTH);
this.drawingColor = ApplicationDomain.IniStorage.GetValue<VideoConfig, RawColor4>(p => p.VIDEO_SELECTION_BOX_BORDER_COLOR);
}
/// <summary>
/// 名称
/// </summary>
public override string Name => VideoControlPluginNames.SelectionBox;
/// <summary>
/// 选中时触发
/// </summary>
public event EventHandler<SelectionBoxSelectedEventArgs> Selected;
/// <summary>
/// 框选框信息
/// </summary>
private volatile SelectionBoxInfo selectionBoxInfo;
/// <summary>
/// 鼠标左键按下的坐标
/// </summary>
private Point? mouseLeftButtonDownPoint;
/// <summary>
/// 绘制颜色
/// </summary>
private RawColor4 drawingColor;
/// <summary>
/// 绘制宽度
/// </summary>
private float drawingWidth;
/// <summary>
/// 更新数据
/// </summary>
/// <param name="trackingBoxInfos">跟踪框信息</param>
public void Update(SelectionBoxInfo selectionBoxInfo)
{
this.selectionBoxInfo = selectionBoxInfo;
}
/// <summary>
/// 渲染
/// </summary>
/// <param name="context">渲染上下文</param>
public override void Render(VideoRenderContext context)
{
SelectionBoxInfo info = this.selectionBoxInfo;
if (info == null)
return;
SolidColorBrush brush = new SolidColorBrush(context.Target, info.DrawingBorderColor);
RawRectangleF rect;
if (context.Mode == VideoRenderMode.UI)
{
rect = info.DrawingRect;
}
else
{
rect = ImageHelper.ConvertUiRectToImageRect(context.VideoRenderInfo.Frame.Width, context.VideoRenderInfo.Frame.Height, context.VideoRenderInfo.DrawingRect, info.DrawingRect.ToRect()).ToRawRectangleF();
}
context.Target.DrawRectangle(rect, brush, info.DrawingBorderWidth);
}
/// <summary>
/// 附加
/// </summary>
public override void Attach()
{
this.VideoRender.PreviewMouseLeftButtonDown -= VideoRender_PreviewMouseLeftButtonDown;
this.VideoRender.PreviewMouseLeftButtonDown += VideoRender_PreviewMouseLeftButtonDown;
this.VideoRender.PreviewMouseLeftButtonUp -= VideoRender_PreviewMouseLeftButtonUp;
this.VideoRender.PreviewMouseLeftButtonUp += VideoRender_PreviewMouseLeftButtonUp;
this.VideoRender.PreviewMouseMove -= VideoRender_PreviewMouseMove;
this.VideoRender.PreviewMouseMove += VideoRender_PreviewMouseMove;
}
/// <summary>
/// 卸载
/// </summary>
public override void Detach()
{
this.VideoRender.PreviewMouseLeftButtonDown -= VideoRender_PreviewMouseLeftButtonDown;
}
/// <summary>
/// 鼠标左键点击
/// </summary>
private void VideoRender_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (!this.IsEnabled)
return;
this.mouseLeftButtonDownPoint = e.GetPosition(this.VideoRender);
}
/// <summary>
/// 鼠标左键抬起
/// </summary>
private void VideoRender_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (this.mouseLeftButtonDownPoint == null || !this.IsEnabled)
return;
VideoRenderInfo renderInfo = this.VideoRender.RenderInfo;
if (renderInfo == null)
{
this.selectionBoxInfo = null;
return;
}
if (this.Selected == null)
return;
Point beginPoint = this.mouseLeftButtonDownPoint.Value;
Point endPoint = e.GetPosition(this.VideoRender);
this.mouseLeftButtonDownPoint = null;
SelectionBoxSelectedEventArgs args = new SelectionBoxSelectedEventArgs();
float left = (float)Math.Min(beginPoint.X, endPoint.X);
float right = (float)Math.Max(beginPoint.X, endPoint.X);
float top = (float)Math.Min(beginPoint.Y, endPoint.Y);
float bottom = (float)Math.Max(beginPoint.Y, endPoint.Y);
args.DrawingRect = new RawRectangleF(left, top, right, bottom);
args.SrcRect = ImageHelper.ConvertUiRectToImageRect(renderInfo.Frame.Width, renderInfo.Frame.Height, renderInfo.DrawingRect, args.DrawingRect.ToRect()).ToRawRectangleF();
this.Selected.Invoke(this, args);
}
/// <summary>
/// 鼠标移动
/// </summary>
private void VideoRender_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (this.mouseLeftButtonDownPoint == null || !this.IsEnabled)
return;
Point beginPoint = this.mouseLeftButtonDownPoint.Value;
Point endPoint = e.GetPosition(this.VideoRender);
float left = (float)Math.Min(beginPoint.X, endPoint.X);
float right = (float)Math.Max(beginPoint.X, endPoint.X);
float top = (float)Math.Min(beginPoint.Y, endPoint.Y);
float bottom = (float)Math.Max(beginPoint.Y, endPoint.Y);
SelectionBoxInfo info = new SelectionBoxInfo();
info.DrawingRect = new RawRectangleF(left, top, right, bottom);
info.DrawingBorderColor = this.drawingColor;
info.DrawingBorderWidth = this.drawingWidth;
this.selectionBoxInfo = info;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace VIZ.Framework.Common
{
/// <summary>
/// 跟踪框点击事件参数
/// </summary>
public class TrackingBoxClickEventArgs : EventArgs
{
/// <summary>
/// 鼠标点击位置
/// </summary>
public Point MousePoint { get; set; }
/// <summary>
/// 命中的跟踪框信息
/// </summary>
public List<TrackingBoxInfo> HitTrackingBoxInfos { get; set; }
}
}
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 跟踪框信息
/// </summary>
public class TrackingBoxInfo
{
/// <summary>
/// 编号
/// </summary>
public string ID { get; set; }
/// <summary>
/// 源区域
/// </summary>
public RawRectangleF SrcRect { get; set; }
/// <summary>
/// 绘制边框颜色
/// </summary>
public RawColor4 DrawingBorderColor { get; set; }
/// <summary>
/// 绘制边框宽度
/// </summary>
public float DrawingBorderWidth { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 跟踪框扩展
/// </summary>
public static class TrackingBoxExpand
{
/// <summary>
/// 更新跟踪框
/// </summary>
/// <param name="videoControl">视频控件</param>
/// <param name="trackingBoxInfos">跟踪框信息</param>
public static void UpdateTrackingBox(this VideoControl videoControl, List<TrackingBoxInfo> trackingBoxInfos)
{
if (videoControl.videoRender == null)
return;
TrackingBoxPlugin plugin = videoControl.GetPlugin<TrackingBoxPlugin>(VideoControlPluginNames.TrackingBox);
if (plugin == null)
return;
plugin.Update(trackingBoxInfos);
}
/// <summary>
/// 清理跟踪框
/// </summary>
/// <param name="videoControl">视频控件</param>
public static void ClearTrackingBox(this VideoControl videoControl)
{
if (videoControl.videoRender == null)
return;
TrackingBoxPlugin plugin = videoControl.GetPlugin<TrackingBoxPlugin>(VideoControlPluginNames.TrackingBox);
if (plugin == null)
return;
plugin.Update(null);
}
/// <summary>
/// 命中测试
/// </summary>
/// <param name="trackingBoxInfos">跟踪框信息结合</param>
/// <param name="point">视频坐标</param>
/// <returns>命中的跟踪框</returns>
public static List<TrackingBoxInfo> HitTest(List<TrackingBoxInfo> trackingBoxInfos, System.Windows.Point point)
{
List<TrackingBoxInfo> result = new List<TrackingBoxInfo>();
if (trackingBoxInfos == null || trackingBoxInfos.Count == 0)
return result;
foreach (TrackingBoxInfo item in trackingBoxInfos)
{
if (point.X >= item.SrcRect.Left && point.X <= item.SrcRect.Right && point.Y >= item.SrcRect.Top && point.Y <= item.SrcRect.Bottom)
{
result.Add(item);
}
}
return result;
}
}
}
using SharpDX.Direct2D1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VIZ.Framework.Core;
namespace VIZ.Framework.Common
{
/// <summary>
/// 跟踪框插件
/// </summary>
public class TrackingBoxPlugin : VideoPluginBase
{
/// <summary>
/// 跟踪框插件
/// </summary>
/// <param name="videoControl">视频控件</param>
public TrackingBoxPlugin(VideoControl videoControl) : base(videoControl)
{
}
/// <summary>
/// 名称
/// </summary>
public override string Name => VideoControlPluginNames.TrackingBox;
/// <summary>
/// 点击跟踪框时触发
/// </summary>
public event EventHandler<TrackingBoxClickEventArgs> TrackingBoxClick;
/// <summary>
/// 跟踪框信息
/// </summary>
private volatile List<TrackingBoxInfo> trackingBoxInfos;
/// <summary>
/// 更新数据
/// </summary>
/// <param name="trackingBoxInfos">跟踪框信息</param>
public void Update(List<TrackingBoxInfo> trackingBoxInfos)
{
this.trackingBoxInfos = trackingBoxInfos;
}
/// <summary>
/// 渲染
/// </summary>
/// <param name="context">渲染上下文</param>
public override void Render(VideoRenderContext context)
{
// 画面渲染区域
List<TrackingBoxInfo> infos = this.trackingBoxInfos;
if (infos == null)
return;
foreach (TrackingBoxInfo info in infos)
{
// 跟踪框绘制区域转化为UI绘制区域
SharpDX.Mathematics.Interop.RawRectangleF rect;
if (context.Mode == VideoRenderMode.UI)
{
Rect drawRect = ImageHelper.ConvertImageRectToUiRect(context.VideoRenderInfo.Frame.Width, context.VideoRenderInfo.Frame.Height, context.VideoRenderInfo.DrawingRect, info.SrcRect.ToRect());
rect = drawRect.ToRawRectangleF();
}
else
{
rect = info.SrcRect;
}
// 绘制跟踪框
SolidColorBrush brush = new SolidColorBrush(context.Target, info.DrawingBorderColor);
context.Target.DrawRectangle(rect, brush, info.DrawingBorderWidth);
}
}
/// <summary>
/// 附加
/// </summary>
public override void Attach()
{
this.VideoRender.PreviewMouseLeftButtonDown -= VideoRender_PreviewMouseLeftButtonDown;
this.VideoRender.PreviewMouseLeftButtonDown += VideoRender_PreviewMouseLeftButtonDown;
}
/// <summary>
/// 卸载
/// </summary>
public override void Detach()
{
this.VideoRender.PreviewMouseLeftButtonDown -= VideoRender_PreviewMouseLeftButtonDown;
}
/// <summary>
/// 鼠标左键点击
/// </summary>
private void VideoRender_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (this.TrackingBoxClick == null || !this.IsEnabled)
return;
VideoRenderInfo renderInfo = this.VideoRender.RenderInfo;
if (renderInfo == null)
return;
Point uiPoint = e.GetPosition(this.VideoRender);
Point bmpPoint = ImageHelper.ConvertUiPointToImagePoint(renderInfo.Frame.Width, renderInfo.Frame.Height, renderInfo.DrawingRect, uiPoint);
TrackingBoxClickEventArgs args = new TrackingBoxClickEventArgs();
args.MousePoint = uiPoint;
args.HitTrackingBoxInfos = TrackingBoxExpand.HitTest(this.trackingBoxInfos, bmpPoint);
// 触发视频矩形框点击事件
this.TrackingBoxClick.Invoke(this, args);
}
}
}
using SharpDX.Direct2D1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频插件基类
/// </summary>
public abstract class VideoPluginBase : IVideoPlugin
{
/// <summary>
/// 视频插件基类
/// </summary>
/// <param name="videoControl">视频控件</param>
public VideoPluginBase(VideoControl videoControl)
{
this.VideoControl = videoControl;
this.VideoRender = videoControl.videoRender;
}
/// <summary>
/// 插件名称
/// </summary>
public abstract string Name { get; }
/// <summary>
/// 视频控件
/// </summary>
public VideoControl VideoControl { get; private set; }
/// <summary>
/// 视频渲染
/// </summary>
public VideoCustomRender VideoRender { get; private set; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 附加
/// </summary>
public virtual void Attach()
{
}
/// <summary>
/// 卸载
/// </summary>
public virtual void Detach()
{
}
/// <summary>
/// 渲染
/// </summary>
/// <param name="context">渲染上下文</param>
public abstract void Render(VideoRenderContext context);
}
}
<UserControl x:Class="VIZ.Framework.Common.VideoControl"
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"
xmlns:common="clr-namespace:VIZ.Framework.Common"
xmlns:converter="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
mc:Ignorable="d" x:Name="uc"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converter:Bool2VisibilityConverter x:Key="Bool2VisibilityConverter"></converter:Bool2VisibilityConverter>
</UserControl.Resources>
<Grid>
<common:VideoCustomRender x:Name="videoRender"></common:VideoCustomRender>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5,5,0,0" IsHitTestVisible="False"
Visibility="{Binding Path=IsShowFPS,ElementName=uc,Converter={StaticResource Bool2VisibilityConverter}}">
<TextBlock Text="FPS:" Foreground="Red" FontSize="24"></TextBlock>
<TextBlock Text="{Binding ElementName=videoRender,Path=Fps}" Foreground="Red" FontSize="24" Margin="10,0,0,0"></TextBlock>
</StackPanel>
</Grid>
</UserControl>
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
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 VIZ.Framework.Core;
namespace VIZ.Framework.Common
{
/// <summary>
/// VideoControl.xaml 的交互逻辑
/// </summary>
public partial class VideoControl : UserControl
{
public VideoControl()
{
InitializeComponent();
this.videoRender.OwnerVideoControl = this;
}
// ===========================================================================================================
// === Property ===
// ===========================================================================================================
#region IsShowFPS -- 是否显示FPS
/// <summary>
/// 是否显示FPS
/// </summary>
public bool IsShowFPS
{
get { return (bool)GetValue(IsShowFPSProperty); }
set { SetValue(IsShowFPSProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for IsShowFPS. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty IsShowFPSProperty =
DependencyProperty.Register("IsShowFPS", typeof(bool), typeof(VideoControl), new PropertyMetadata(false));
#endregion
// ===========================================================================================================
// === Public Function ===
// ===========================================================================================================
/// <summary>
/// 更新视频帧
/// </summary>
public void UpdateVideoFrame(IVideoFrame videoFrame)
{
this.videoRender?.UpdateVideoFrame(videoFrame);
}
/// <summary>
/// 清理视频帧
/// </summary>
public void ClearVideoFrame()
{
this.videoRender.UpdateVideoFrame(null);
}
/// <summary>
/// 渲染帧至图片
/// </summary>
/// <param name="plugins">需要处理渲染的插件名称<see cref="VideoControlPluginNames"/></param>
/// <returns>图片</returns>
public Mat RenderVideoToMat(List<string> plugins = null)
{
VideoRenderInfo renderInfo = this.videoRender.RenderInfo;
if (renderInfo == null)
return null;
return this.RenderVideoToMat(renderInfo.Frame.Width, renderInfo.Frame.Height, plugins);
}
/// <summary>
/// 渲染帧至图片
/// </summary>
/// <param name="width">图片宽度</param>
/// <param name="height">图片高度</param>
/// <param name="format">渲染格式</param>
/// <param name="plugins">需要处理渲染的插件名称<see cref="VideoControlPluginNames"/></param>
/// <returns>图片</returns>
public Mat RenderVideoToMat(int width, int height, List<string> plugins = null)
{
SharpDX.WIC.Bitmap bmp = WicBitmapHelper.RenderToBitmap(width, height, this.videoRender.Render, plugins);
Mat mat = new Mat(height, width, MatType.CV_8UC4);
unsafe
{
bmp.CopyPixels(width * 4, new IntPtr(mat.DataPointer), width * height * 4);
}
return mat;
}
/// <summary>
/// 附加插件
/// </summary>
/// <param name="plugin">插件</param>
public void AttachPlugin(IVideoPlugin plugin)
{
lock (this.videoRender.Plugins)
{
this.videoRender.Plugins.Add(plugin);
plugin.Attach();
}
}
/// <summary>
/// 卸载
/// </summary>
/// <param name="name">插件名称</param>
public void DetachPlugin(string name)
{
IVideoPlugin plugin = this.videoRender.Plugins.FirstOrDefault(p => p.Name == name);
if (plugin == null)
return;
lock (this.videoRender.Plugins)
{
this.videoRender.Plugins.Remove(plugin);
plugin.Detach();
}
}
/// <summary>
/// 卸载所有插件
/// </summary>
public void DetachPluginAll()
{
lock (this.videoRender.Plugins)
{
foreach (IVideoPlugin plugin in this.videoRender.Plugins)
{
plugin.Detach();
}
this.videoRender.Plugins.Clear();
}
}
/// <summary>
/// 获取插件
/// </summary>
/// <typeparam name="T">插件类型</typeparam>
/// <param name="name">插件名称</param>
/// <returns>插件</returns>
public T GetPlugin<T>(string name) where T : class, IVideoPlugin
{
return this.videoRender.Plugins.FirstOrDefault(p => p.Name == name) as T;
}
/// <summary>
/// 获取渲染信息
/// </summary>
public VideoRenderInfo GetRenderInfo()
{
return this.videoRender.RenderInfo;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频控件插件名称
/// </summary>
public static class VideoControlPluginNames
{
/// <summary>
/// 跟踪框
/// </summary>
public const string TrackingBox = "TrackingBox";
/// <summary>
/// 框选框
/// </summary>
public const string SelectionBox = "SelectionBox";
/// <summary>
/// 裁剪框
/// </summary>
public const string ClipBox = "ClipBox";
}
}
using SharpDX.Direct2D1;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using VIZ.Framework.Storage;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频自定义渲染
/// ---------------------------------------------
/// 1. 视频帧渲染
/// 2. 矩形框信息渲染
/// 3. 渲染帧至图片
/// ---------------------------------------------
/// </summary>
public class VideoCustomRender : D2dControl
{
// ========================================================================================================
// === Property ===
// ========================================================================================================
/// <summary>
/// 是否启用视频帧渲染
/// </summary>
public bool IsRenderVideoFrameEnabled { get; set; } = true;
/// <summary>
/// 背景颜色
/// </summary>
private readonly RawColor4 BackgroundColor = ApplicationDomain.IniStorage.GetValue<VideoConfig, RawColor4>(p => p.VIDEO_BACKGROUND_COLOR);
// ========================================================================================================
/// <summary>
/// 所属渲染控件
/// </summary>
internal VideoControl OwnerVideoControl { get; set; }
/// <summary>
/// 待渲染信息
/// </summary>
internal volatile VideoRenderInfo RenderInfo;
/// <summary>
/// 插件集合
/// </summary>
internal List<IVideoPlugin> Plugins = new List<IVideoPlugin>();
/// <summary>
/// 渲染锁对象
/// </summary>
private object render_lock_object = new object();
// ========================================================================================================
// === Public Function ===
// ========================================================================================================
/// <summary>
/// 更新视频帧
/// </summary>
/// <param name="videoFrame">视频帧</param>
public void UpdateVideoFrame(IVideoFrame videoFrame)
{
if (videoFrame == null)
{
this.RenderInfo = null;
return;
}
// ----------------------------------------------------------------------------------------
// 计算绘制区域与大小
ImageHelper.AdjustSize((int)this.ActualWidth, (int)this.ActualHeight, videoFrame.Width, videoFrame.Height, out int width, out int height);
int x = (int)((this.ActualWidth - width) / 2);
int y = (int)((this.ActualHeight - height) / 2);
// ----------------------------------------------------------------------------------------
// 绘制信息
VideoRenderInfo info = new VideoRenderInfo();
info.Frame = videoFrame;
info.ControlRect = new Rect(0, 0, this.ActualWidth, this.ActualHeight);
info.DrawingRect = new Rect(x, y, width, height);
lock (this.render_lock_object)
{
this.RenderInfo?.Dispose();
this.RenderInfo = info;
}
}
// ========================================================================================================
/// <summary>
/// 渲染
/// </summary>
/// <param name="target">渲染目标</param>
public override void Render(RenderTarget target)
{
VideoRenderContext context = new VideoRenderContext();
context.Target = target;
context.Mode = VideoRenderMode.UI;
this.Render(context);
}
/// <summary>
/// 渲染
/// </summary>
/// <param name="context">渲染上下文</param>
public void Render(VideoRenderContext context)
{
lock (this.render_lock_object)
{
context.Target.Clear(this.BackgroundColor);
VideoRenderInfo renderInfo = this.RenderInfo;
if (renderInfo == null)
return;
context.VideoRenderInfo = renderInfo;
// 绘制视频
if (this.IsRenderVideoFrameEnabled)
{
this.RenderVideoFrame(context);
}
// 插件渲染
foreach (IVideoPlugin plugin in this.Plugins)
{
if (!plugin.IsEnabled)
continue;
if (context.Mode == VideoRenderMode.Image && (context.RenderImagePlugins == null || !context.RenderImagePlugins.Contains(plugin.Name)))
continue;
plugin.Render(context);
}
}
}
/// <summary>
/// 绘制视频
/// </summary>
/// <param name="context">渲染上下文</param>
private void RenderVideoFrame(VideoRenderContext context)
{
BitmapProperties properties = new BitmapProperties(new SharpDX.Direct2D1.PixelFormat(Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied));
SharpDX.Size2 size = new SharpDX.Size2(context.VideoRenderInfo.Frame.Width, context.VideoRenderInfo.Frame.Height);
SharpDX.Direct2D1.Bitmap bmp = new SharpDX.Direct2D1.Bitmap(context.Target, size, context.VideoRenderInfo.Frame.DataStream, context.VideoRenderInfo.Frame.Width * 4, properties);
if (context.Mode == VideoRenderMode.UI)
{
context.Target.DrawBitmap(bmp, context.VideoRenderInfo.DrawingRect.ToRawRectangleF(), 1f, BitmapInterpolationMode.Linear, null);
}
else
{
SharpDX.Mathematics.Interop.RawRectangleF rect = new SharpDX.Mathematics.Interop.RawRectangleF(0, 0, context.VideoRenderInfo.Frame.Width, context.VideoRenderInfo.Frame.Height);
context.Target.DrawBitmap(bmp, rect, 1f, BitmapInterpolationMode.Linear, null);
}
bmp.Dispose();
}
}
}
using SharpDX.Direct2D1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频渲染上下文
/// </summary>
public class VideoRenderContext
{
/// <summary>
/// 渲染目标
/// </summary>
public RenderTarget Target { get; set; }
/// <summary>
/// 视频渲染信息
/// </summary>
public VideoRenderInfo VideoRenderInfo { get; set; }
/// <summary>
/// 渲染模式
/// </summary>
public VideoRenderMode Mode { get; set; }
/// <summary>
/// 需要渲染至图片的插件
/// </summary>
public List<string> RenderImagePlugins { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using SharpDX;
using SharpDX.Direct2D1;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频渲染信息
/// </summary>
public class VideoRenderInfo : IDisposable
{
/// <summary>
/// 视频帧信息
/// </summary>
public IVideoFrame Frame { get; set; }
/// <summary>
/// 渲染区域
/// </summary>
public Rect DrawingRect { get; set; }
/// <summary>
/// 控件区域
/// </summary>
public Rect ControlRect { get; set; }
/// <summary>
/// 该对象是否已经被销毁
/// </summary>
private bool IsDisopsed { get; set; }
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
if (this.IsDisopsed)
return;
this.IsDisopsed = true;
this.Frame?.Dispose();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频渲染模式
/// </summary>
public enum VideoRenderMode
{
/// <summary>
/// 渲染至UI
/// </summary>
UI,
/// <summary>
/// 渲染至图片文件
/// </summary>
Image
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
using SharpDX.Direct2D1;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频帧
/// </summary>
public interface IVideoFrame : IDisposable
{
/// <summary>
/// 宽度
/// </summary>
int Width { get; set; }
/// <summary>
/// 高度
/// </summary>
int Height { get; set; }
/// <summary>
/// 数据长度
/// </summary>
int Length { get; set; }
/// <summary>
/// 时间戳
/// </summary>
long TimeStamp { get; set; }
/// <summary>
/// 是否是最后一帧
/// </summary>
bool IsEnd { get; set; }
/// <summary>
/// 画面数据
/// </summary>
DataStream DataStream { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频流
/// </summary>
public interface IVideoStream : IDisposable
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NewTek;
namespace VIZ.Framework.Common
{
/// <summary>
/// NDI流 静态部分
/// </summary>
public partial class NDIStream
{
/// <summary>
/// 是否完成了初始化
/// </summary>
public static bool IsInited { get; private set; }
/// <summary>
/// 初始化
/// </summary>
/// <returns>是否初始化成功</returns>
public static bool Init()
{
if (!NDIlib.initialize())
return false;
IsInited = true;
return true;
}
public static void Destroy()
{
if (!IsInited)
return;
NDIlib.destroy();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using NewTek;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using NewTek.NDI;
namespace VIZ.Framework.Common
{
/// <summary>
/// NDI流
/// </summary>
public partial class NDIStream : VideoStreamBase<NDIStreamOption>
{
/// <summary>
/// NDI流
/// </summary>
/// <param name="localRecevierName">本地接收者名称</param>
/// <param name="remoteSenderName">远程发送者名称</param>
/// <param name="option">设置</param>
public NDIStream(string localRecevierName, string remoteSenderName, NDIStreamOption option)
: base(option)
{
this.LocalRecevierName = localRecevierName;
this.RemoteSenderName = remoteSenderName;
// 查找NDI流任务
this.TaskDic.Add(NDIStreamTaskNames.FIND_STREAM, new NDIStreamFindStreamTask(this));
// 接收视频帧任务
this.TaskDic.Add(NDIStreamTaskNames.RECV_VIDEO, new NDIStreamRecvVideoTask(this));
// 处理视频帧任务
this.TaskDic.Add(NDIStreamTaskNames.EXECUTE_VIDEO, new NDIStreamExecuteVideoTask(this));
}
/* ========================================================================================================= */
/* === Const === */
/* ========================================================================================================= */
/// <summary>
/// the size of an NDIlib.source_t, for pointer offsets
/// </summary>
public readonly int SOURCE_SIZE_IN_BYTES = Marshal.SizeOf(typeof(NDIlib.source_t));
/* ========================================================================================================= */
/* === Property === */
/* ========================================================================================================= */
/// <summary>
/// NDI流信息集合
/// </summary>
public List<NDIStreamInfo> StreamInfos { get; private set; } = new List<NDIStreamInfo>();
/// <summary>
/// 远程NDI发送者名称
/// </summary>
public string RemoteSenderName { get; private set; }
/// <summary>
/// 本地NDI接收者名称
/// </summary>
public string LocalRecevierName { get; private set; }
/* ========================================================================================================= */
/* === Internal Field === */
/* ========================================================================================================= */
/// <summary>
/// 查找NDI流实例句柄
/// </summary>
internal IntPtr FindInstancePtr;
/// <summary>
/// 当前正在处理的NDI流源
/// </summary>
internal NDIlib.source_t? CurrentRemoteSenderSource;
/// <summary>
/// 接收NDI流实例句柄
/// </summary>
internal IntPtr RecvInstancePtr;
/// <summary>
/// 接收NDI流同步信息实例句柄
/// </summary>
internal IntPtr RecvSyncInstancePtr;
/* ========================================================================================================= */
/* === Field === */
/* ========================================================================================================= */
/// <summary>
/// 任务池
/// </summary>
private Dictionary<NDIStreamTaskNames, NDIStreamTaskBase> TaskDic = new Dictionary<NDIStreamTaskNames, NDIStreamTaskBase>();
/* ========================================================================================================= */
/* === Function === */
/* ========================================================================================================= */
/// <summary>
/// 开始
/// </summary>
public void Start()
{
NDIlib.find_create_t findCreateDesc = new NDIlib.find_create_t();
findCreateDesc.p_groups = IntPtr.Zero;
findCreateDesc.show_local_sources = true;
findCreateDesc.p_extra_ips = IntPtr.Zero;
// 创建NDI流查找实例句柄
this.FindInstancePtr = NDIlib.find_create_v2(ref findCreateDesc);
// 启动NDI流查找任务
this.TaskDic[NDIStreamTaskNames.FIND_STREAM].Start();
// 启动NDI视频帧接收任务
this.TaskDic[NDIStreamTaskNames.RECV_VIDEO].Start();
// 启动NDI视频帧处理任务
this.TaskDic[NDIStreamTaskNames.EXECUTE_VIDEO].Start();
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
// 停止所有任务
foreach (var task in this.TaskDic.Values)
{
task.Stop();
}
// 重置当前NDI流信息
this.CurrentRemoteSenderSource = null;
// 清理流信息
lock (this.StreamInfos)
{
this.StreamInfos.Clear();
}
// 释放查找NDI流句柄
if (this.FindInstancePtr != IntPtr.Zero)
{
NDIlib.find_destroy(this.FindInstancePtr);
this.FindInstancePtr = IntPtr.Zero;
}
// 释放接收NDI流实例句柄
if (this.RecvInstancePtr != IntPtr.Zero)
{
NDIlib.recv_destroy(this.RecvInstancePtr);
this.RecvInstancePtr = IntPtr.Zero;
}
// 释放NDI流同步接收实例句柄
if (this.RecvSyncInstancePtr != IntPtr.Zero)
{
NDIlib.framesync_destroy(this.RecvSyncInstancePtr);
this.RecvSyncInstancePtr = IntPtr.Zero;
}
}
/// <summary>
/// 销毁
/// </summary>
public override void Dispose()
{
this.Stop();
}
/// <summary>
/// 切换远程发送者名称
/// </summary>
/// <param name="remoteSenderName">远程发送者名称</param>
/// <returns>是否成功切换</returns>
public bool ChangeRemoteSenderName(string remoteSenderName)
{
// -------------------------------------------------------------------------------
// 获取将要切换的NDI流信息
// 获取要切换的NDI流信息
NDIStreamInfo info = null;
lock (this.StreamInfos)
{
info = this.StreamInfos.FirstOrDefault(p => p.FullName == remoteSenderName);
}
if (info == null)
{
return false;
}
// -------------------------------------------------------------------------------
// 释放
// 释放接收NDI流实例句柄
if (this.RecvInstancePtr != IntPtr.Zero)
{
NDIlib.recv_destroy(this.RecvInstancePtr);
this.RecvInstancePtr = IntPtr.Zero;
}
// 释放NDI流同步接收实例句柄
if (this.RecvSyncInstancePtr != IntPtr.Zero)
{
NDIlib.framesync_destroy(this.RecvSyncInstancePtr);
this.RecvSyncInstancePtr = IntPtr.Zero;
}
// -------------------------------------------------------------------------------
// 初始化
// 设置NDI发送者名称
this.RemoteSenderName = remoteSenderName;
// 设置当前NDI发送源
this.CurrentRemoteSenderSource = info.Source;
// 创建NDI接收实例句柄 & NDI同步接收实例对象
NDIlib.recv_create_v3_t recvCreateDesc = new NDIlib.recv_create_v3_t();
recvCreateDesc.source_to_connect_to = info.Source;
recvCreateDesc.color_format = NDIlib.recv_color_format_e.recv_color_format_BGRX_BGRA;
recvCreateDesc.bandwidth = NDIlib.recv_bandwidth_e.recv_bandwidth_highest;
recvCreateDesc.allow_video_fields = false;
recvCreateDesc.p_ndi_recv_name = UTF.StringToUtf8(this.LocalRecevierName);
this.RecvInstancePtr = NDIlib.recv_create_v3(ref recvCreateDesc);
this.RecvSyncInstancePtr = NDIlib.framesync_create(this.RecvInstancePtr);
// -------------------------------------------------------------------------------
// 切换成功
return true;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NewTek;
namespace VIZ.Framework.Common
{
/// <summary>
/// NDI流信息
/// </summary>
public class NDIStreamInfo
{
/// <summary>
/// 机器
/// </summary>
public string Machine { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 完整名称
/// </summary>
public string FullName { get; set; }
/// <summary>
/// NDI流信息
/// </summary>
public NDIlib.source_t Source { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// NDI流设置
/// </summary>
public class NDIStreamOption : VideoStreamOptionBase
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace VIZ.Framework.Common
{
/// <summary>
/// NDI流任务
/// </summary>
public abstract class NDIStreamTaskBase : VideoStreamTaskBase
{
/// <summary>
/// NDI工具任务
/// </summary>
/// <param name="stream">NDI流</param>
public NDIStreamTaskBase(NDIStream stream)
{
this.Stream = stream;
}
/// <summary>
/// 任务名称
/// </summary>
public abstract NDIStreamTaskNames Name { get; }
/// <summary>
/// NDI工具
/// </summary>
public NDIStream Stream { get; private set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// NDI流任务名称
/// </summary>
public enum NDIStreamTaskNames
{
/// <summary>
/// 查找NDI流
/// </summary>
FIND_STREAM,
/// <summary>
/// 接收视频
/// </summary>
RECV_VIDEO,
/// <summary>
/// 处理视频帧
/// </summary>
EXECUTE_VIDEO
}
}
using NewTek;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
using OpenCvSharp;
namespace VIZ.Framework.Common
{
/// <summary>
/// NDI视频帧
/// </summary>
public class NDIStreamVideoFrame : VideoFrameBase
{
/// <summary>
/// NDI视频帧
/// </summary>
public NDIStreamVideoFrame()
{ }
/// <summary>
/// NDI视频帧
/// </summary>
/// <param name="color">颜色</param>
public NDIStreamVideoFrame(Scalar color) : base(color)
{ }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using NewTek;
namespace VIZ.Framework.Common
{
/// <summary>
/// 处理NDI视频帧任务
/// </summary>
public class NDIStreamExecuteVideoTask : NDIStreamTaskBase
{
/// <summary>
/// 处理NDI视频帧任务
/// </summary>
/// <param name="stream">NDI流</param>
public NDIStreamExecuteVideoTask(NDIStream stream) : base(stream)
{
}
/// <summary>
/// 任务名称
/// </summary>
public override NDIStreamTaskNames Name => NDIStreamTaskNames.EXECUTE_VIDEO;
/// <summary>
/// 执行
/// </summary>
protected override void Execute()
{
while (this.IsStarted)
{
if (this.Stream.VideoFrameQueue.Count <= this.Stream.Option.DelayFrame)
{
Thread.Sleep(2);
continue;
}
if (!this.Stream.VideoFrameQueue.TryDequeue(out IVideoFrame frame))
{
continue;
}
// 触发视频帧处理事件
this.Stream.TriggerExecuteVideoFrame(frame);
Thread.Sleep(10);
}
}
}
}
using NewTek;
using NewTek.NDI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 查找NDI流任务
/// </summary>
public class NDIStreamFindStreamTask : NDIStreamTaskBase
{
/// <summary>
/// 查找NDI流任务
/// </summary>
/// <param name="stream">NDI流</param>
public NDIStreamFindStreamTask(NDIStream stream) : base(stream)
{
}
/// <summary>
/// 任务名称
/// </summary>
public override NDIStreamTaskNames Name => NDIStreamTaskNames.FIND_STREAM;
/// <summary>
/// the size of an NDIlib.source_t, for pointer offsets
/// </summary>
private readonly int SOURCE_SIZE_IN_BYTES = Marshal.SizeOf(typeof(NDIlib.source_t));
/// <summary>
/// 执行
/// </summary>
protected override void Execute()
{
while (this.IsStarted)
{
this._Execute();
}
}
/// <summary>
/// 执行
/// </summary>
private void _Execute()
{
if (!NDIlib.find_wait_for_sources(this.Stream.FindInstancePtr, 500))
return;
lock (this.Stream.StreamInfos)
{
this.Stream.StreamInfos.Clear();
}
uint numSources = 0;
IntPtr sourcesPtr = NDIlib.find_get_current_sources(this.Stream.FindInstancePtr, ref numSources);
for (int i = 0; i < numSources; i++)
{
// 连续的数据结构
IntPtr p = IntPtr.Add(sourcesPtr, (i * SOURCE_SIZE_IN_BYTES));
// 指针转化为 NDIlib.source_t 数据结构
NDIlib.source_t src = (NDIlib.source_t)Marshal.PtrToStructure(p, typeof(NDIlib.source_t));
// NDI流名称
string ndiName = UTF.Utf8ToString(src.p_ndi_name);
// 添加NDI流信息
NDIStreamInfo info = new NDIStreamInfo();
info.FullName = ndiName;
info.Machine = ndiName.Split(new char[] { ' ' }, 2)[0];
info.Name = ndiName.Substring(ndiName.IndexOf(' ') + 1);
info.Source = src;
lock (this.Stream.StreamInfos)
{
this.Stream.StreamInfos.Add(info);
}
}
// 如果当前没有正在处理的流信息那么切换为当前RemoteSenderName指定的流信息
if (this.Stream.CurrentRemoteSenderSource == null)
{
this.Stream.ChangeRemoteSenderName(this.Stream.RemoteSenderName);
}
}
}
}
using NewTek;
using NewTek.NDI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
namespace VIZ.Framework.Common
{
/// <summary>
/// 查找NDI流任务
/// </summary>
public class NDIStreamRecvVideoTask : NDIStreamTaskBase
{
/// <summary>
/// 查找NDI流任务
/// </summary>
/// <param name="stream">NDI流</param>
public NDIStreamRecvVideoTask(NDIStream stream) : base(stream)
{
}
/// <summary>
/// 任务名称
/// </summary>
public override NDIStreamTaskNames Name => NDIStreamTaskNames.RECV_VIDEO;
/// <summary>
/// 之前的视频帧时间戳
/// </summary>
private long old_video_timestamp = 0;
/// <summary>
/// 执行
/// </summary>
protected override void Execute()
{
while (this.IsStarted)
{
if (this.Stream.RecvInstancePtr == IntPtr.Zero || this.Stream.RecvSyncInstancePtr == IntPtr.Zero)
{
Thread.Sleep(1);
continue;
}
// 执行
this._Execute();
}
}
/// <summary>
/// 执行
/// </summary>
private void _Execute()
{
// 获取NDI视频帧
NDIlib.video_frame_v2_t frame = new NDIlib.video_frame_v2_t();
NDIlib.framesync_capture_video(this.Stream.RecvSyncInstancePtr, ref frame, NDIlib.frame_format_type_e.frame_format_type_progressive);
// 如果该帧的时间戳与之前的帧时间戳一致
// 那么认为没有获取到新的一帧画面
if (this.old_video_timestamp == frame.timestamp)
{
NDIlib.framesync_free_video(this.Stream.RecvSyncInstancePtr, ref frame);
Thread.Sleep(1);
return;
}
// 否则
// 获取到新的一帧画面
this.old_video_timestamp = frame.timestamp;
// 如果新的一帧画面的时间戳为0 || 帧没有数据
if (frame.timestamp == 0 || frame.p_data == IntPtr.Zero || frame.p_data == null)
{
NDIlib.framesync_free_video(this.Stream.RecvSyncInstancePtr, ref frame);
Thread.Sleep(1);
return;
}
// 视频帧队列最大容量
// 如果超过该容量,那么会抛弃对队列头部的处理
if (this.Stream.VideoFrameQueue.Count > NDIStream.VIDEO_FRAME_QUEUE_MAX_COUNT + this.Stream.Option.DelayFrame)
{
this.Stream.VideoFrameQueue.TryDequeue(out IVideoFrame remove);
remove?.Dispose();
}
NDIStreamVideoFrame videoFrame = new NDIStreamVideoFrame();
videoFrame.Width = frame.xres;
videoFrame.Height = frame.yres;
videoFrame.Length = frame.xres * frame.yres * 4;
videoFrame.TimeStamp = frame.timestamp;
videoFrame.DataStream = new SharpDX.DataStream(videoFrame.Length, true, true);
unsafe
{
Buffer.MemoryCopy(frame.p_data.ToPointer(), videoFrame.DataStream.DataPointer.ToPointer(), videoFrame.Length, videoFrame.Length);
}
this.Stream.VideoFrameQueue.Enqueue(videoFrame);
// 尝试释放帧数据
NDIlib.framesync_free_video(this.Stream.RecvSyncInstancePtr, ref frame);
Thread.Sleep(5);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// OpenCV属性信息
/// </summary>
public class OpenCVPropertyInfos
{
/// <summary>
/// Fps
/// </summary>
public double Fps { get; internal set; }
/// <summary>
/// 帧宽度
/// </summary>
public double FrameWidth { get; internal set; }
/// <summary>
/// 帧高度
/// </summary>
public double FrameHeight { get; internal set; }
/// <summary>
/// 帧数
/// </summary>
public double FrameCount { get; internal set; }
}
}
using OpenCvSharp;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
namespace VIZ.Framework.Common
{
/// <summary>
/// OpenCv流
/// </summary>
public class OpenCVStream : VideoStreamBase<OpenCVStreamOption>
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(OpenCVStream));
/// <summary>
/// OpenCv流
/// </summary>
/// <param name="option">设置</param>
public OpenCVStream(OpenCVStreamOption option) : base(option)
{
this.TaskDic.Add(OpenCVStreamTaskNames.RECV_VIDEO, new OpenCVStreamRecvVideoTask(this));
this.TaskDic.Add(OpenCVStreamTaskNames.EXECUTE_VIDEO, new OpenCVStreamExecuteVideoTask(this));
}
/* ========================================================================================================= */
/* === Property === */
/* ========================================================================================================= */
/// <summary>
/// 地址
/// </summary>
public string Uri { get; private set; }
/// <summary>
/// 属性信息
/// </summary>
public OpenCVPropertyInfos PropertyInfos { get; private set; }
/// <summary>
/// 状态
/// </summary>
public OpenCVStreamStatus Status { get; private set; }
/* ========================================================================================================= */
/* === Internal Field === */
/* ========================================================================================================= */
/// <summary>
/// 视频捕获
/// </summary>
internal VideoCapture VideoCapture;
/// <summary>
/// 读取帧锁对象
/// </summary>
internal object read_frame_lock_object = new object();
/* ========================================================================================================= */
/* === Field === */
/* ========================================================================================================= */
/// <summary>
/// 任务池
/// </summary>
private Dictionary<OpenCVStreamTaskNames, OpenCVStreamTaskBase> TaskDic = new Dictionary<OpenCVStreamTaskNames, OpenCVStreamTaskBase>();
/* ========================================================================================================= */
/* === Function === */
/* ========================================================================================================= */
/// <summary>
/// 播放
/// </summary>
public void Play()
{
if (this.Status == OpenCVStreamStatus.None || this.Status == OpenCVStreamStatus.Play)
return;
double frame = this.VideoCapture.Get(VideoCaptureProperties.PosFrames);
if (frame >= this.PropertyInfos.FrameCount)
{
this.Stop();
}
foreach (var task in this.TaskDic.Values)
{
task.Start();
}
this.Status = OpenCVStreamStatus.Play;
}
/// <summary>
/// 暂停
/// </summary>
public void Pause()
{
if (this.Status == OpenCVStreamStatus.None || this.Status == OpenCVStreamStatus.Stop)
return;
foreach (var task in this.TaskDic.Values)
{
task.Stop();
}
this.Status = OpenCVStreamStatus.Pause;
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
if (this.Status == OpenCVStreamStatus.None)
return;
foreach (var task in this.TaskDic.Values)
{
task.Stop();
}
this.VideoCapture.Set(VideoCaptureProperties.PosFrames, 0);
this.TriggerExecuteBlackVideoFrame();
this.Status = OpenCVStreamStatus.Stop;
}
/// <summary>
/// 设置位置
/// </summary>
/// <param name="position">帧位置</param>
public void SetPosition(int position)
{
if (this.Status == OpenCVStreamStatus.None)
return;
lock (this.read_frame_lock_object)
{
this.VideoCapture.Set(VideoCaptureProperties.PosFrames, position);
while (this.VideoFrameQueue.Count > 0)
{
if (this.VideoFrameQueue.TryDequeue(out IVideoFrame frame))
{
frame.Dispose();
}
}
}
}
/// <summary>
/// 切换源
/// </summary>
/// <param name="uri">源</param>
public void ChangeUri(string uri)
{
this.Stop();
this.Uri = uri;
this.VideoCapture?.Dispose();
this.VideoCapture = null;
if (string.IsNullOrWhiteSpace(uri))
{
this.Status = OpenCVStreamStatus.None;
this.PropertyInfos = null;
return;
}
try
{
this.VideoCapture = new VideoCapture(this.Uri);
this.InitPropertyInfos();
}
catch (Exception ex)
{
log.Error(ex);
this.Status = OpenCVStreamStatus.None;
this.PropertyInfos = null;
}
this.Status = OpenCVStreamStatus.Stop;
}
/// <summary>
/// 触发执行黑色帧
/// </summary>
public void TriggerExecuteBlackVideoFrame()
{
OpenCVStreeamVideoFrame frame = new OpenCVStreeamVideoFrame(Scalar.Black);
this.TriggerExecuteVideoFrame(frame);
}
/// <summary>
/// 触发执行第一帧
/// </summary>
public void TriggerExecuteCurrentPosVideoFrame()
{
if (this.Status == OpenCVStreamStatus.None)
return;
OpenCVStreeamVideoFrame videoFrame = new OpenCVStreeamVideoFrame();
lock (this.read_frame_lock_object)
{
Mat src = new Mat();
Mat mat = new Mat();
if (!this.VideoCapture.Read(src))
{
src.Dispose();
return;
}
Cv2.CvtColor(src, mat, ColorConversionCodes.BGR2BGRA);
videoFrame.Width = mat.Width;
videoFrame.Height = mat.Height;
videoFrame.Length = mat.Width * mat.Height * 4;
videoFrame.TimeStamp = TimeSpan.FromMilliseconds(this.VideoCapture.PosMsec).Ticks;
videoFrame.DataStream = new SharpDX.DataStream(videoFrame.Length, true, true);
unsafe
{
Buffer.MemoryCopy(mat.DataPointer, videoFrame.DataStream.DataPointer.ToPointer(), videoFrame.Length, videoFrame.Length);
}
src.Dispose();
mat.Dispose();
}
this.TriggerExecuteVideoFrame(videoFrame);
}
/// <summary>
/// 销毁
/// </summary>
public override void Dispose()
{
foreach (var task in this.TaskDic.Values)
{
task.Dispose();
}
this.VideoCapture?.Dispose();
}
/* ========================================================================================================= */
/* === Internal Function === */
/* ========================================================================================================= */
/* ========================================================================================================= */
/* === Private Function === */
/* ========================================================================================================= */
/// <summary>
/// 初始化属性信息
/// </summary>
private void InitPropertyInfos()
{
OpenCVPropertyInfos infos = new OpenCVPropertyInfos();
// FPS
infos.Fps = this.VideoCapture.Get(VideoCaptureProperties.Fps);
// 帧宽度
infos.FrameWidth = this.VideoCapture.Get(VideoCaptureProperties.FrameWidth);
// 帧高度
infos.FrameHeight = this.VideoCapture.Get(VideoCaptureProperties.FrameHeight);
// 帧数量
infos.FrameCount = this.VideoCapture.Get(VideoCaptureProperties.FrameCount);
this.PropertyInfos = infos;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// OpenCV流设置
/// </summary>
public class OpenCVStreamOption : VideoStreamOptionBase
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// OpenCV流状态
/// </summary>
public enum OpenCVStreamStatus
{
/// <summary>
/// 未指定,不可用
/// </summary>
None,
/// <summary>
/// 播放状态
/// </summary>
Play,
/// <summary>
/// 暂停状态
/// </summary>
Pause,
/// <summary>
/// 停止状态
/// </summary>
Stop
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// OpenCV流任务基类
/// </summary>
public abstract class OpenCVStreamTaskBase : VideoStreamTaskBase
{
/// <summary>
/// OpenCV工具任务基类
/// </summary>
/// <param name="stream">OpenCV流</param>
public OpenCVStreamTaskBase(OpenCVStream stream)
{
this.Stream = stream;
}
/// <summary>
/// 任务名称
/// </summary>
public abstract OpenCVStreamTaskNames Name { get; }
/// <summary>
/// OpenCV流
/// </summary>
public OpenCVStream Stream { get; private set; }
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// OpenCV任务名称
/// </summary>
public enum OpenCVStreamTaskNames
{
/// <summary>
/// 接收视频
/// </summary>
RECV_VIDEO,
/// <summary>
/// 处理视频帧
/// </summary>
EXECUTE_VIDEO
}
}
using SharpDX;
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
namespace VIZ.Framework.Common
{
/// <summary>
/// OpenCV视频帧
/// </summary>
public class OpenCVStreeamVideoFrame : VideoFrameBase
{
/// <summary>
/// OpenCV视频帧
/// </summary>
public OpenCVStreeamVideoFrame()
{ }
/// <summary>
/// OpenCV视频帧
/// </summary>
/// <param name="color">颜色</param>
public OpenCVStreeamVideoFrame(Scalar color) : base(color)
{ }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using NewTek;
namespace VIZ.Framework.Common
{
/// <summary>
/// 处理OpenCV视频帧任务
/// </summary>
public class OpenCVStreamExecuteVideoTask : OpenCVStreamTaskBase
{
/// <summary>
/// 处理NDI视频帧任务
/// </summary>
/// <param name="stream">OpenCV流</param>
public OpenCVStreamExecuteVideoTask(OpenCVStream stream) : base(stream)
{
}
/// <summary>
/// 任务名称
/// </summary>
public override OpenCVStreamTaskNames Name => OpenCVStreamTaskNames.EXECUTE_VIDEO;
/// <summary>
/// 执行
/// </summary>
protected override void Execute()
{
while (this.IsStarted)
{
if (this.Stream.VideoFrameQueue.Count <= this.Stream.Option.DelayFrame)
{
Thread.Sleep(2);
continue;
}
if (!this.Stream.VideoFrameQueue.TryDequeue(out IVideoFrame frame))
{
continue;
}
// 触发视频帧处理事件
this.Stream.TriggerExecuteVideoFrame(frame);
Thread.Sleep(10);
}
}
}
}
using NewTek;
using NewTek.NDI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
using OpenCvSharp;
using System.Diagnostics;
namespace VIZ.Framework.Common
{
/// <summary>
/// OpenCV接收视频任务
/// </summary>
public class OpenCVStreamRecvVideoTask : OpenCVStreamTaskBase
{
/// <summary>
/// OpenCV接收视频任务
/// </summary>
/// <param name="stream">OpenCV流</param>
public OpenCVStreamRecvVideoTask(OpenCVStream stream) : base(stream)
{
}
/// <summary>
/// 任务名称
/// </summary>
public override OpenCVStreamTaskNames Name => OpenCVStreamTaskNames.RECV_VIDEO;
/// <summary>
/// 计时器
/// </summary>
private readonly Stopwatch renderTimer = new Stopwatch();
/// <summary>
/// 执行
/// </summary>
protected override void Execute()
{
while (this.IsStarted)
{
long begin = this.renderTimer.ElapsedMilliseconds;
this.renderTimer.Start();
lock (this.Stream.read_frame_lock_object)
{
// 处理一帧
this.ExecuteOne();
}
this.renderTimer.Stop();
long end = this.renderTimer.ElapsedMilliseconds;
int wait = (int)((1000d / this.Stream.PropertyInfos.Fps) - (end - begin));
if (wait > 0)
{
Thread.Sleep(wait);
}
}
}
/// <summary>
/// 执行一帧
/// </summary>
public void ExecuteOne()
{
Mat src = new Mat();
Mat mat = new Mat();
if (!this.Stream.VideoCapture.Read(src))
{
src.Dispose();
Thread.Sleep(5);
return;
}
Cv2.CvtColor(src, mat, ColorConversionCodes.BGR2BGRA);
OpenCVStreeamVideoFrame videoFrame = new OpenCVStreeamVideoFrame();
videoFrame.Width = mat.Width;
videoFrame.Height = mat.Height;
videoFrame.Length = mat.Width * mat.Height * 4;
videoFrame.TimeStamp = TimeSpan.FromMilliseconds(this.Stream.VideoCapture.PosMsec).Ticks;
videoFrame.DataStream = new SharpDX.DataStream(videoFrame.Length, true, true);
videoFrame.IsEnd = this.Stream.VideoCapture.PosFrames == this.Stream.PropertyInfos.FrameCount;
unsafe
{
Buffer.MemoryCopy(mat.DataPointer, videoFrame.DataStream.DataPointer.ToPointer(), videoFrame.Length, videoFrame.Length);
}
this.Stream.VideoFrameQueue.Enqueue(videoFrame);
src.Dispose();
mat.Dispose();
}
}
}
using OpenCvSharp;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频帧基类
/// </summary>
public abstract class VideoFrameBase : IVideoFrame
{
/// <summary>
/// 视频帧基类
/// </summary>
public VideoFrameBase()
{ }
/// <summary>
/// 视频帧基类
/// </summary>
/// <param name="color">颜色</param>
public VideoFrameBase(Scalar color)
{
this.Width = 1;
this.Height = 1;
this.Length = 4;
this.DataStream = new DataStream(this.Length, true, true);
Mat mat = new Mat(1, 1, MatType.CV_8UC4, color);
unsafe
{
Buffer.MemoryCopy(mat.DataPointer, this.DataStream.DataPointer.ToPointer(), this.Length, this.Length);
}
mat.Dispose();
}
/// <summary>
/// 宽度
/// </summary>
public int Width { get; set; }
/// <summary>
/// 高度
/// </summary>
public int Height { get; set; }
/// <summary>
/// 数据长度
/// </summary>
public int Length { get; set; }
/// <summary>
/// 时间戳
/// </summary>
public long TimeStamp { get; set; }
/// <summary>
/// 是否是最后一帧
/// </summary>
public bool IsEnd { get; set; }
/// <summary>
/// 画面数据
/// </summary>
public DataStream DataStream { get; set; }
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this.DataStream?.Dispose();
this.DataStream = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频帧事件参数
/// </summary>
public class VideoFrameEventArgs : EventArgs
{
/// <summary>
/// 视频帧数据
/// </summary>
public IVideoFrame Frame { get; set; }
}
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX.Mathematics.Interop;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频流基类
/// </summary>
/// <typeparam name="TOption">设置类型</typeparam>
public abstract class VideoStreamBase<TOption> : IVideoStream, IDisposable where TOption : VideoStreamOptionBase
{
/// <summary>
/// 视频流基类
/// </summary>
/// <param name="option">设置</param>
public VideoStreamBase(TOption option)
{
this.Option = option;
}
/* ========================================================================================================= */
/* === Const === */
/* ========================================================================================================= */
/// <summary>
/// 视频帧队列最大容量
/// 如果超过该容量,那么会抛弃对队列头部的处理
/// </summary>
public const int VIDEO_FRAME_QUEUE_MAX_COUNT = 8;
/* ========================================================================================================= */
/* === Event === */
/* ========================================================================================================= */
/// <summary>
/// 处理视频帧事件
/// </summary>
public event EventHandler<VideoFrameEventArgs> ExecuteVideoFrame;
/* ========================================================================================================= */
/* === Property === */
/* ========================================================================================================= */
/// <summary>
/// 设置
/// </summary>
public TOption Option { get; private set; }
/* ========================================================================================================= */
/* === Internal Field === */
/* ========================================================================================================= */
/// <summary>
/// 视频帧队列
/// </summary>
internal ConcurrentQueue<IVideoFrame> VideoFrameQueue = new ConcurrentQueue<IVideoFrame>();
/* ========================================================================================================= */
/* === Internal Function === */
/* ========================================================================================================= */
/// <summary>
/// 触发执行视频帧事件
/// </summary>
/// <param name="frame">视频帧</param>
internal void TriggerExecuteVideoFrame(IVideoFrame frame)
{
if (this.ExecuteVideoFrame == null)
return;
VideoFrameEventArgs args = new VideoFrameEventArgs();
args.Frame = frame;
this.ExecuteVideoFrame.Invoke(this, args);
}
/* ========================================================================================================= */
/* === Public Function === */
/* ========================================================================================================= */
/// <summary>
/// 销毁
/// </summary>
public abstract void Dispose();
/// <summary>
/// 设置视频帧延时
/// </summary>
/// <param name="delayFrame">延时帧</param>
public void SetVideoFrameDelay(int delayFrame)
{
this.Option.DelayFrame = delayFrame;
while (this.VideoFrameQueue.Count > VIDEO_FRAME_QUEUE_MAX_COUNT + this.Option.DelayFrame)
{
this.VideoFrameQueue.TryDequeue(out IVideoFrame remove);
remove?.Dispose();
}
}
/* ========================================================================================================= */
/* === Protected Function === */
/* ========================================================================================================= */
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频流管理器
/// </summary>
public static class VideoStreamManager
{
/// <summary>
/// 池
/// </summary>
private static Dictionary<string, IVideoStream> pool = new Dictionary<string, IVideoStream>();
/// <summary>
/// 添加视频流工具
/// </summary>
/// <param name="key">建</param>
/// <param name="stream">视频流</param>
public static void Append(string key, IVideoStream stream)
{
lock (pool)
{
if (pool.ContainsKey(key))
throw new Exception($"key: {key}, is already exists");
pool[key] = stream;
}
}
/// <summary>
/// 获取视频流
/// </summary>
/// <typeparam name="T">视频流类型</typeparam>
/// <param name="key">键</param>
/// <returns>视频流</returns>
public static T Get<T>(string key) where T : class, IVideoStream
{
pool.TryGetValue(key, out IVideoStream stream);
return stream as T;
}
/// <summary>
/// 移除视频流
/// </summary>
/// <param name="key">键</param>
public static void Remove(string key)
{
lock (pool)
{
if (pool.ContainsKey(key))
{
pool.Remove(key);
}
}
}
/// <summary>
/// 清理所有视频流
/// </summary>
public static void Clear()
{
lock (pool)
{
pool.Clear();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频流设置基类
/// </summary>
public abstract class VideoStreamOptionBase
{
/// <summary>
/// 延时帧
/// </summary>
public int DelayFrame { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频流任务基类
/// </summary>
public abstract class VideoStreamTaskBase : IDisposable
{
/// <summary>
/// 是否开启
/// </summary>
public bool IsStarted { get; set; }
/// <summary>
/// 任务线程
/// </summary>
private Thread Thread;
/// <summary>
/// 开始
/// </summary>
public virtual void Start()
{
if (this.IsStarted)
throw new Exception("task is already started.");
this.IsStarted = true;
this.Thread = new Thread(this.Execute);
this.Thread.IsBackground = true;
this.Thread.Start();
}
/// <summary>
/// 停止
/// </summary>
public virtual void Stop()
{
this.IsStarted = false;
this.Thread = null;
}
/// <summary>
/// 销毁
/// </summary>
public virtual void Dispose()
{
this.Stop();
}
/// <summary>
/// 执行
/// </summary>
protected abstract void Execute();
}
}
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 VIZ.Framework.Common
{
/// <summary>
/// 颜色拾取按钮
/// </summary>
public class ColorPickButton : Button
{
static ColorPickButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPickButton), new FrameworkPropertyMetadata(typeof(ColorPickButton)));
}
#region Color -- 颜色
/// <summary>
/// 颜色
/// </summary>
public Color Color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Color. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register("Color", typeof(Color), typeof(ColorPickButton), new PropertyMetadata(Colors.Red, new PropertyChangedCallback((s, e) =>
{
(s as ColorPickButton).Background = new SolidColorBrush((Color)e.NewValue);
})));
#endregion
protected override void OnClick()
{
base.OnClick();
System.Windows.Forms.ColorDialog cd = new System.Windows.Forms.ColorDialog();
if (cd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
return;
string color_str = $"#{cd.Color.A.ToString("X2")}{cd.Color.R.ToString("X2")}{cd.Color.G.ToString("X2")}{cd.Color.B.ToString("X2")}";
this.Color = (Color)ColorConverter.ConvertFromString(color_str);
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VIZ.Framework.Common">
<Style TargetType="local:ColorPickButton">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ColorPickButton">
<Border Background="{TemplateBinding Background}"></Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
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.Input;
using VIZ.Framework.Core;
namespace VIZ.Framework.Common
{
/// <summary>
/// 拖拽窗口区域
/// </summary>
public class DragWindowBar : Border
{
/// <summary>
/// 鼠标按下的坐标
/// </summary>
private Point? mouseLeftButtonDownPoint;
/// <summary>
/// 所属窗口
/// </summary>
private Window ownerWindow;
/// <summary>
/// 获取所属窗口
/// </summary>
/// <returns>所属窗口</returns>
private Window GetOwnerWindow()
{
if (this.ownerWindow != null)
return this.ownerWindow;
this.ownerWindow = WPFHelper.GetAncestorByType<Window>(this);
return this.ownerWindow;
}
/// <summary>
/// 鼠标按下
/// </summary>
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonDown(e);
this.mouseLeftButtonDownPoint = e.GetPosition(this);
}
/// <summary>
/// 鼠标移动
/// </summary>
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
if (e.LeftButton != MouseButtonState.Pressed || this.mouseLeftButtonDownPoint == null)
return;
Point point = e.GetPosition(this);
if (Math.Abs(point.X - this.mouseLeftButtonDownPoint.Value.X) >= 5 || Math.Abs(point.Y - this.mouseLeftButtonDownPoint.Value.Y) >= 5)
{
Window window = this.GetOwnerWindow();
window.DragMove();
}
}
/// <summary>
/// 鼠标释放
/// </summary>
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonUp(e);
this.mouseLeftButtonDownPoint = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
namespace VIZ.Framework.Common
{
/// <summary>
/// 导航配置
/// </summary>
public class NavigationConfig : ModelBase
{
#region Key --
private string key;
/// <summary>
/// 键
/// </summary>
public string Key
{
get { return key; }
set { key = value; this.RaisePropertyChanged(nameof(Key)); }
}
#endregion
#region ViewType -- 视图类型
private Type viewType;
/// <summary>
/// 视图类型
/// </summary>
public Type ViewType
{
get { return viewType; }
set { viewType = value; this.RaisePropertyChanged(nameof(ViewType)); }
}
#endregion
}
}
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.Controls.Primitives;
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 VIZ.Framework.Common
{
/// <summary>
/// 导航控件
/// </summary>
public class NavigationControl : ListBox
{
static NavigationControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigationControl), new FrameworkPropertyMetadata(typeof(NavigationControl)));
}
protected override DependencyObject GetContainerForItemOverride()
{
NavigationItemControl itemControl = new NavigationItemControl();
return itemControl;
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is NavigationItemControl;
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
xmlns:local="clr-namespace:VIZ.Framework.Common">
<core:Bool2VisibilityConverter x:Key="Bool2VisibilityConverter" TrueVisibility="Visible" FalseVisibility="Hidden"></core:Bool2VisibilityConverter>
<Style TargetType="local:NavigationItemControl">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="Visibility" Value="{Binding Path=IsSelected,RelativeSource={RelativeSource Mode=Self},Converter={StaticResource Bool2VisibilityConverter}}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:NavigationItemControl">
<ContentPresenter></ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="NavigationItemControlItem" TargetType="local:NavigationItemControl">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="Visibility" Value="{Binding Path=IsSelected,RelativeSource={RelativeSource Mode=Self},Converter={StaticResource Bool2VisibilityConverter}}"></Setter>
<Setter Property="ViewType" Value="{Binding Path=ViewType,Mode=OneWay}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:NavigationItemControl">
<ContentPresenter></ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:NavigationControl">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="ItemContainerStyle" Value="{StaticResource NavigationItemControlItem}"></Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Grid></Grid>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:NavigationControl">
<ItemsPresenter></ItemsPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
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 VIZ.Framework.Common
{
/// <summary>
/// 导航项控件
/// </summary>
public class NavigationItemControl : ListBoxItem
{
static NavigationItemControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigationItemControl), new FrameworkPropertyMetadata(typeof(NavigationItemControl)));
}
public NavigationItemControl()
{
this.IsVisibleChanged += NavigationItemControl_IsVisibleChanged;
}
#region Key --
/// <summary>
/// 键
/// </summary>
public string Key
{
get { return (string)GetValue(KeyProperty); }
set { SetValue(KeyProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Key. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty KeyProperty =
DependencyProperty.Register("Key", typeof(string), typeof(NavigationItemControl), new PropertyMetadata(null));
#endregion
#region ViewType -- 视图类型
/// <summary>
/// 视图类型
/// </summary>
public Type ViewType
{
get { return (Type)GetValue(ViewTypeProperty); }
set { SetValue(ViewTypeProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for ViewType. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty ViewTypeProperty =
DependencyProperty.Register("ViewType", typeof(Type), typeof(NavigationItemControl), new PropertyMetadata(null));
#endregion
/// <summary>
/// 可见性改变时触发
/// </summary>
private void NavigationItemControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (!this.IsVisible)
return;
if (this.Content != null && this.Content.GetType() == this.ViewType)
return;
if (this.ViewType != null)
{
this.Content = this.ViewType.Assembly.CreateInstance(this.ViewType.FullName);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
namespace VIZ.Framework.Common
{
/// <summary>
/// 空窗口
/// </summary>
public class NoneWindow : Window
{
/// <summary>
/// 窗口
/// </summary>
/// <param name="width">窗口宽度</param>
/// <param name="height">窗口高度</param>
/// <param name="content">窗口内容</param>
public NoneWindow(double width, double height, Control content)
{
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
this.WindowState = WindowState.Normal;
this.WindowStyle = WindowStyle.None;
this.Background = new SolidColorBrush(Colors.Transparent);
this.AllowsTransparency = true;
this.Width = width;
this.Height = height;
this.Content = content;
content.Margin = new Thickness(10, 10, 10, 10);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
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 VIZ.Framework.Common
{
/// <summary>
/// 数字输入框
/// </summary>
[TemplatePart(Name = nameof(PART_Up), Type = typeof(RepeatButton))]
[TemplatePart(Name = nameof(PART_Down), Type = typeof(RepeatButton))]
public class NumberBox : TextBox
{
static NumberBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumberBox), new FrameworkPropertyMetadata(typeof(NumberBox)));
}
public NumberBox()
{
this.SetCurrentValue(NumberBox.TextProperty, this.MinValue.ToString());
}
#region MinValue -- 最小值
/// <summary>
/// 最小值
/// </summary>
public double MinValue
{
get { return (double)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for MinValue. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(double), typeof(NumberBox), new PropertyMetadata(0d));
#endregion
#region MaxValue -- 最大值
/// <summary>
/// 最大值
/// </summary>
public double MaxValue
{
get { return (double)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for MaxValue. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(double), typeof(NumberBox), new PropertyMetadata(100d));
#endregion
#region Value -- 当前值
/// <summary>
/// 当前值
/// </summary>
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(NumberBox), new PropertyMetadata(0d, new PropertyChangedCallback((s, e) =>
{
(s as NumberBox).Text = ((double)e.NewValue).ToString();
})));
#endregion
#region Interval -- 间隔值
/// <summary>
/// 间隔值
/// </summary>
public double Interval
{
get { return (double)GetValue(IntervalProperty); }
set { SetValue(IntervalProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Interval. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty IntervalProperty =
DependencyProperty.Register("Interval", typeof(double), typeof(NumberBox), new PropertyMetadata(1d));
#endregion
#region IsShowUpAndDownButton -- 是否显示上下按钮
/// <summary>
/// 是否显示上下按钮
/// </summary>
public bool IsShowUpAndDownButton
{
get { return (bool)GetValue(IsShowUpAndDownButtonProperty); }
set { SetValue(IsShowUpAndDownButtonProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for IsShowUpAndDownButton. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty IsShowUpAndDownButtonProperty =
DependencyProperty.Register("IsShowUpAndDownButton", typeof(bool), typeof(NumberBox), new PropertyMetadata(true));
#endregion
/// <summary>
/// 向上按钮
/// </summary>
private RepeatButton PART_Up;
/// <summary>
/// 向下按钮
/// </summary>
private RepeatButton PART_Down;
/// <summary>
/// 应用模板
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.PART_Up = this.Template.FindName(nameof(PART_Up), this) as RepeatButton;
this.PART_Down = this.Template.FindName(nameof(PART_Down), this) as RepeatButton;
if (this.PART_Up != null)
{
this.PART_Up.Click -= PART_Up_Click;
this.PART_Up.Click += PART_Up_Click;
}
if (this.PART_Down != null)
{
this.PART_Down.Click -= PART_Down_Click;
this.PART_Down.Click += PART_Down_Click;
}
}
/// <summary>
/// 文本改变之后
/// </summary>
protected override void OnTextChanged(TextChangedEventArgs e)
{
base.OnTextChanged(e);
if (string.IsNullOrWhiteSpace(this.Text))
{
this.Text = "0";
return;
}
if (!double.TryParse(this.Text, out double value))
{
this.Text = this.Value.ToString();
}
else if (value < this.MinValue)
{
this.Value = this.MinValue;
}
else if (value > this.MaxValue)
{
this.Value = this.MaxValue;
}
else
{
this.Value = value;
}
}
/// <summary>
/// 向下
/// </summary>
private void PART_Down_Click(object sender, RoutedEventArgs e)
{
double value = this.Value - this.Interval;
if (value < this.MinValue || value > this.MaxValue)
return;
this.Text = value.ToString();
}
/// <summary>
/// 向上
/// </summary>
private void PART_Up_Click(object sender, RoutedEventArgs e)
{
double value = this.Value + this.Interval;
if (value < this.MinValue || value > this.MaxValue)
return;
this.Text = value.ToString();
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
xmlns:local="clr-namespace:VIZ.Framework.Common">
<core:Bool2VisibilityConverter x:Key="Bool2VisibilityConverter" TrueVisibility="Visible" FalseVisibility="Collapsed"></core:Bool2VisibilityConverter>
<Style TargetType="local:NumberBox">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:NumberBox">
<Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" Margin="5,0,5,0"
VerticalScrollBarVisibility="Hidden" VerticalContentAlignment="Center" Grid.RowSpan="2"/>
<RepeatButton x:Name="PART_Up" Width="60"
Visibility="{TemplateBinding IsShowUpAndDownButton,Converter={StaticResource Bool2VisibilityConverter}}"
Grid.Column="1" Grid.Row="0" Content="Up"></RepeatButton>
<RepeatButton x:Name="PART_Down" Width="60"
Visibility="{TemplateBinding IsShowUpAndDownButton,Converter={StaticResource Bool2VisibilityConverter}}"
Grid.Column="1" Grid.Row="1" Content="Down"></RepeatButton>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频时间条值改变时间参数
/// </summary>
public class VideoTimeBarValueChangedEventArgs : EventArgs
{
/// <summary>
/// 最大时间
/// </summary>
public TimeSpan MaxTime { get; set; }
/// <summary>
/// 当前时间
/// </summary>
public TimeSpan Time { get; set; }
}
}
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;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using log4net;
namespace VIZ.Framework.Common
{
/// <summary>
/// 视频播放器时间条
/// </summary>
[TemplatePart(Name = nameof(PART_Slider), Type = typeof(Slider))]
[TemplatePart(Name = nameof(PART_Copy), Type = typeof(FrameworkElement))]
public class VideoTimeBar : Control, IDisposable
{
static VideoTimeBar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(VideoTimeBar), new FrameworkPropertyMetadata(typeof(VideoTimeBar)));
}
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(VideoTimeBar));
/// <summary>
/// TimeSpan格式化字符串
/// </summary>
private static readonly string TIME_SPAN_FORMAT = "hh\\:mm\\:ss";
/// <summary>
/// 视频播放器时间条
/// </summary>
public VideoTimeBar()
{
}
// ======================================================================================
// === Field ===
// ======================================================================================
/// <summary>
/// 进度条
/// </summary>
private Slider PART_Slider;
/// <summary>
/// 拷贝控件
/// </summary>
private FrameworkElement PART_Copy;
/// <summary>
/// 是否正在等待手动改变值
/// </summary>
private bool isWaitManualValueChanging;
/// <summary>
/// 手动改变值时触发
/// </summary>
public event EventHandler<VideoTimeBarValueChangedEventArgs> TimeBarManualValueChanged;
// ======================================================================================
// === Property ===
// ======================================================================================
#region MaxTime -- 最大时间
/// <summary>
/// 最大时间
/// </summary>
public TimeSpan MaxTime
{
get { return (TimeSpan)GetValue(MaxTimeProperty); }
set { SetValue(MaxTimeProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for MaxTime. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty MaxTimeProperty =
DependencyProperty.Register("MaxTime", typeof(TimeSpan), typeof(VideoTimeBar), new PropertyMetadata(TimeSpan.Zero, new PropertyChangedCallback((s, e) =>
{
(s as VideoTimeBar).TryUpdateSliderMaxValue();
})));
#endregion
#region Time -- 时间
/// <summary>
/// 时间
/// </summary>
public TimeSpan Time
{
get { return (TimeSpan)GetValue(TimeProperty); }
set { SetValue(TimeProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Time. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty TimeProperty =
DependencyProperty.Register("Time", typeof(TimeSpan), typeof(VideoTimeBar), new PropertyMetadata(TimeSpan.Zero, new PropertyChangedCallback((s, e) =>
{
(s as VideoTimeBar).TryUpdateSliderValue();
})));
#endregion
#region TimeString -- 时间字符串
/// <summary>
/// 时间字符串
/// </summary>
public string TimeString
{
get { return (string)GetValue(TimeStringProperty); }
set { SetValue(TimeStringProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for TimeString. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty TimeStringProperty =
DependencyProperty.Register("TimeString", typeof(string), typeof(VideoTimeBar), new PropertyMetadata(TimeSpan.Zero.ToString(TIME_SPAN_FORMAT)));
#endregion
// ======================================================================================
// === Public Function ===
// ======================================================================================
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
ApplicationDomain.LoopManager.UnRegister($"VideoTimeBar_{this.GetHashCode()}");
}
// ======================================================================================
// === Override Function ===
// ======================================================================================
/// <summary>
/// 应用模板
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.PART_Slider = this.Template.FindName(nameof(this.PART_Slider), this) as Slider;
this.PART_Slider.Minimum = 0d;
this.PART_Slider.PreviewMouseLeftButtonDown -= PART_Slider_PreviewMouseLeftButtonDown;
this.PART_Slider.PreviewMouseLeftButtonDown += PART_Slider_PreviewMouseLeftButtonDown;
this.PART_Slider.PreviewMouseLeftButtonUp -= PART_Slider_PreviewMouseLeftButtonUp;
this.PART_Slider.PreviewMouseLeftButtonUp += PART_Slider_PreviewMouseLeftButtonUp;
this.PART_Slider.ValueChanged -= PART_Slider_ValueChanged;
this.PART_Slider.ValueChanged += PART_Slider_ValueChanged;
this.PART_Copy = this.Template.FindName(nameof(this.PART_Copy), this) as FrameworkElement;
this.PART_Copy.PreviewMouseLeftButtonUp -= PART_Copy_PreviewMouseLeftButtonUp;
this.PART_Copy.PreviewMouseLeftButtonUp += PART_Copy_PreviewMouseLeftButtonUp;
}
// ======================================================================================
// === Private Function ===
// ======================================================================================
/// <summary>
/// 拷贝
/// </summary>
private void PART_Copy_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Clipboard.SetText(this.TimeString);
}
/// <summary>
/// 鼠标左键按下
/// </summary>
private void PART_Slider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.isWaitManualValueChanging = true;
}
/// <summary>
/// 鼠标释放
/// </summary>
private void PART_Slider_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!this.isWaitManualValueChanging)
return;
VideoTimeBarValueChangedEventArgs args = new VideoTimeBarValueChangedEventArgs();
args.MaxTime = this.MaxTime;
args.Time = TimeSpan.FromSeconds(this.PART_Slider.Value);
this.TimeBarManualValueChanged?.Invoke(this, args);
this.isWaitManualValueChanging = false;
}
/// <summary>
/// 进度值改变
/// </summary>
private void PART_Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!this.isWaitManualValueChanging)
return;
this.TimeString = TimeSpan.FromSeconds(this.PART_Slider.Value).ToString(TIME_SPAN_FORMAT);
this.SetCurrentValue(TimeProperty, TimeSpan.FromSeconds(this.PART_Slider.Value));
}
/// <summary>
/// 尝试更新进度值
/// </summary>
private void TryUpdateSliderValue()
{
WPFHelper.BeginInvoke(() =>
{
if (this.isWaitManualValueChanging)
return;
this.PART_Slider.Value = this.Time.TotalSeconds;
this.TimeString = this.Time.ToString(TIME_SPAN_FORMAT);
});
}
/// <summary>
/// 尝试更新进度最大值
/// </summary>
private void TryUpdateSliderMaxValue()
{
this.PART_Slider.Maximum = this.MaxTime.TotalSeconds;
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
xmlns:local="clr-namespace:VIZ.Framework.Common">
<core:TimeSpan2DoubleConverter x:Key="TimeSpan2DoubleConverter" Type="Second"></core:TimeSpan2DoubleConverter>
<Style TargetType="local:VideoTimeBar">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:VideoTimeBar">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="180"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Slider x:Name="PART_Slider" VerticalAlignment="Center"></Slider>
<StackPanel x:Name="PART_Copy" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Horizontal"
ToolTip="点击复制" Cursor="Hand" Background="Transparent">
<TextBlock Text="{Binding Path=TimeString,RelativeSource={RelativeSource AncestorLevel=1,Mode=FindAncestor,AncestorType=local:VideoTimeBar}}"
FontSize="14"></TextBlock>
<TextBlock Text="/" Margin="5,0,5,0"
FontSize="14"></TextBlock>
<TextBlock Text="{Binding Path=MaxTime,RelativeSource={RelativeSource AncestorLevel=1,Mode=FindAncestor,AncestorType=local:VideoTimeBar},StringFormat=hh\\:mm\\:ss}"
FontSize="14"></TextBlock>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.14" targetFramework="net48" />
<package id="OpenCvSharp4" version="4.6.0.20220608" targetFramework="net48" />
<package id="SharpDX" version="4.2.0" targetFramework="net48" />
<package id="SharpDX.Direct2D1" version="4.2.0" targetFramework="net48" />
<package id="SharpDX.Direct3D11" version="4.2.0" targetFramework="net48" />
<package id="SharpDX.Direct3D9" version="4.2.0" targetFramework="net48" />
<package id="SharpDX.DXGI" version="4.2.0" targetFramework="net48" />
<package id="SharpDX.Mathematics" version="4.2.0" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
</packages>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Connection
{
/// <summary>
/// 链接管理器
/// </summary>
public static class ConnectionManager
{
/// <summary>
/// Udp连接
/// </summary>
public static UdpConnection UdpConnection { get; set; }
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("VIZ.Framework.Connection")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.Connection")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("e07528dd-9dee-47c2-b79d-235ecfa6b003")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Connection
{
/// <summary>
/// UDP包处理器
/// </summary>
public interface IUdpPackageProvider
{
/// <summary>
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
void Execute(UdpPackageInfo packageInfo);
}
}
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using VIZ.Framework.Domain;
namespace VIZ.Framework.Connection
{
/// <summary>
/// UDP连接
/// </summary>
public class UdpConnection : IDisposable
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(UdpConnection));
/// <summary>
/// 最大数据长度
/// </summary>
public const int MAX_BUFFER_SIZE = 1024 * 10;
/// <summary>
/// UDP客户端
/// </summary>
public UdpClient UdpClient { get; private set; }
/// <summary>
/// IP地址
/// </summary>
public string IP { get; private set; }
/// <summary>
/// 端口
/// </summary>
public int Port { get; private set; }
/// <summary>
/// 包处理器
/// </summary>
internal List<IUdpPackageProvider> PackageProviders = new List<IUdpPackageProvider>();
#if DEBUG
/// <summary>
/// 调试消息委托
/// </summary>
/// <param name="msg">消息</param>
public delegate void DebugMessageDelegate(string msg);
/// <summary>
/// 调试消息时触发
/// </summary>
public DebugMessageDelegate OnDebugMessage;
#endif
/// <summary>
/// 终结点管理器集合
/// </summary>
private Dictionary<string, UdpEndpointManager> endpointManagers = new Dictionary<string, UdpEndpointManager>();
/// <summary>
/// 数据接收线程
/// </summary>
private Thread recvTrhead;
/// <summary>
/// 是否已经开始接收数据
/// </summary>
private bool IsRecvStart;
/// <summary>
/// 绑定IP和端口
/// </summary>
/// <param name="ip">IP</param>
/// <param name="port">端口</param>
public void Binding(string ip, int port)
{
this.IP = ip;
this.Port = port;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), port);
this.UdpClient = new UdpClient(ipep);
}
/// <summary>
/// 连接
/// </summary>
public void Start()
{
this.IsRecvStart = true;
this.recvTrhead = new Thread(this.ReceiveMessage);
this.recvTrhead.Start();
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
try
{
this.IsRecvStart = false;
this.UdpClient?.Close();
this.UdpClient?.Dispose();
this.recvTrhead = null;
}
catch (Exception ex)
{
log.Error(ex);
}
}
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this.Stop();
}
/// <summary>
/// 添加包处理器
/// </summary>
/// <param name="provider">包处理器</param>
public void AddProvider(IUdpPackageProvider provider)
{
this.PackageProviders.Add(provider);
}
/// <summary>
/// 获取UDP终结点管理器
/// </summary>
/// <param name="key">终结点管理器键</param>
/// <returns>终结点管理器</returns>
public UdpEndpointManager GetEndpointManager(string key)
{
this.endpointManagers.TryGetValue(key, out UdpEndpointManager manager);
return manager;
}
/// <summary>
/// 添加UDP终结点管理器
/// </summary>
/// <param name="manager">终结点管理器</param>
public void AddEndpointManager(UdpEndpointManager manager)
{
manager.UdpClient = this.UdpClient;
manager.UdpConnection = this;
lock (this.endpointManagers)
{
this.endpointManagers[manager.Key] = manager;
}
}
/// <summary>
/// 移除UDP终结点管理器
/// </summary>
/// <param name="key">终结点管理器键</param>
public void RemoveEndpointManager(string key)
{
lock (this.endpointManagers)
{
if (this.endpointManagers.ContainsKey(key))
{
this.endpointManagers.Remove(key);
}
}
}
/// <summary>
/// 接收数据
/// </summary>
/// <param name="obj"></param>
private void ReceiveMessage(object obj)
{
while (this.IsRecvStart)
{
try
{
IPEndPoint endport = new IPEndPoint(IPAddress.Any, 0);
byte[] buffer = this.UdpClient.Receive(ref endport);
UdpPackageInfo info = new UdpPackageInfo();
info.IP = this.IP;
info.Port = this.Port;
info.Message = Encoding.UTF8.GetString(buffer);
foreach (IUdpPackageProvider provider in this.PackageProviders)
{
provider.Execute(info);
}
#if DEBUG
string consoleMsg = $"{DateTime.Now} 【接收】 {info.Message}";
this.OnDebugMessage?.Invoke(consoleMsg);
Debug.WriteLine(consoleMsg);
#endif
UdpConsoleMessage msg = new UdpConsoleMessage();
msg.Message = info.Message;
msg.IsSender = false;
ApplicationDomain.MessageManager.Send(msg);
}
catch (Exception ex)
{
log.Error(ex);
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Diagnostics;
using log4net;
using VIZ.Framework.Domain;
namespace VIZ.Framework.Connection
{
/// <summary>
/// UDP网络终结点管理器
/// </summary>
public class UdpEndpointManager
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(UdpEndpointManager));
/// <summary>
/// 网络终结点键<see cref="UdpEndpointKeys"/>
/// </summary>
public string Key { get; private set; }
/// <summary>
/// 监听IP
/// </summary>
public string IP { get; private set; }
/// <summary>
/// 监听端口
/// </summary>
public int Port { get; private set; }
/// <summary>
/// UDP客户端
/// </summary>
public UdpClient UdpClient { get; internal set; }
/// <summary>
/// UDP连接
/// </summary>
public UdpConnection UdpConnection { get; internal set; }
/// <summary>
/// UDP终结点管理器
/// </summary>
/// <param name="key">网络终结点键<see cref="UdpEndpointKeys"/></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
public UdpEndpointManager(string key, string ip, int port)
{
this.Key = key;
this.IP = ip;
this.Port = port;
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="data">数据</param>
public void Send(string data)
{
byte[] buffer = Encoding.UTF8.GetBytes(data);
this.UdpClient.Send(buffer, buffer.Length, this.IP, this.Port);
#if DEBUG
string consoleMsg = $"{DateTime.Now} 【发送】 {data}";
this.UdpConnection.OnDebugMessage?.Invoke(consoleMsg);
Debug.WriteLine(consoleMsg);
#endif
UdpConsoleMessage msg = new UdpConsoleMessage();
msg.Message = data;
msg.IsSender = true;
ApplicationDomain.MessageManager.Send(msg);
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="data">数据</param>
public void Send(object data)
{
string str = Newtonsoft.Json.JsonConvert.SerializeObject(data);
this.Send(str);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Connection
{
/// <summary>
/// UDP包信息
/// </summary>
public class UdpPackageInfo
{
/// <summary>
/// IP
/// </summary>
public string IP { get; set; }
/// <summary>
/// 端口
/// </summary>
public int Port { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; }
}
}
<?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>{E07528DD-9DEE-47C2-B79D-235ECFA6B003}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VIZ.Framework.Connection</RootNamespace>
<AssemblyName>VIZ.Framework.Connection</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=2.0.14.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.14\lib\net45\log4net.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ConnectionManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UDP\IUdpPackageProvider.cs" />
<Compile Include="UDP\UdpConnection.cs" />
<Compile Include="UDP\UdpEndpointManager.cs" />
<Compile Include="UDP\UdpPackageInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.14" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
</packages>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace VIZ.Framework.Core
{
/// <summary>
/// Bitmap转ImageSource转化器
/// </summary>
public class Bitmap2ImageSourceConverter : IValueConverter
{
[DllImport("gdi32.dll", SetLastError = true)]
private static extern bool DeleteObject(IntPtr hObject);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Bitmap bitmap = value as Bitmap;
if (bitmap == null)
return null;
IntPtr hBitmap = bitmap.GetHbitmap();
ImageSource wpfBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
if (!DeleteObject(hBitmap))
{
throw new System.ComponentModel.Win32Exception();
}
return wpfBitmap;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows;
namespace VIZ.Framework.Core
{
/// <summary>
/// Bool --> Bool 转化器
/// </summary>
public class Bool2BoolConverter : IValueConverter
{
/// <summary>
/// 当值为True时的返回值
/// </summary>
public bool? TrueResult { get; set; } = false;
/// <summary>
/// 当值为False时的返回值
/// </summary>
public bool? FalseResult { get; set; } = true;
/// <summary>
/// 当值为Null时的返回值
/// </summary>
public bool NullResult { get; set; } = true;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool?)
{
bool? b = (bool?)value;
if (b == null)
return this.NullResult;
return b.Value ? this.TrueResult : this.FalseResult;
}
else if (value is bool)
{
bool b = (bool)value;
return b ? this.TrueResult : this.FalseResult;
}
else
{
return this.NullResult;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows;
namespace VIZ.Framework.Core
{
/// <summary>
/// Bool --> Visibility 转化器
/// </summary>
public class Bool2VisibilityConverter : IValueConverter
{
/// <summary>
/// 当值为True时的Visibility值
/// </summary>
public Visibility TrueVisibility { get; set; } = Visibility.Visible;
/// <summary>
/// 当值为False时的Visibility值
/// </summary>
public Visibility FalseVisibility { get; set; } = Visibility.Collapsed;
/// <summary>
/// 当值为Null时的Visibility值
/// </summary>
public Visibility NullVisibility { get; set; } = Visibility.Collapsed;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool?)
{
bool? b = (bool?)value;
if (b == null)
return this.NullVisibility;
return b.Value ? this.TrueVisibility : this.FalseVisibility;
}
else if (value is bool)
{
bool b = (bool)value;
return b ? this.TrueVisibility : this.FalseVisibility;
}
else
{
return this.NullVisibility;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace VIZ.Framework.Core
{
/// <summary>
/// 字节大小类型
/// </summary>
public enum ByteSizeType
{
B = 0,
KB = 1,
MB = 2,
GB = 3
}
/// <summary>
/// 字节大小转化器
/// </summary>
public class ByteSizeConverter : IValueConverter
{
/// <summary>
/// 输入类型
/// </summary>
public ByteSizeType InType { get; set; } = ByteSizeType.B;
/// <summary>
/// 输出类型
/// </summary>
public ByteSizeType OutType { get; set; } = ByteSizeType.B;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return 0d;
if (!double.TryParse(value.ToString(), out double v))
{
return 0d;
}
int _in = (int)this.InType;
int _out = (int)this.OutType;
while (_in != _out)
{
if (_in < _out)
{
v /= 1024f;
++_in;
}
else
{
v *= 1024f;
--_in;
}
}
return v;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return 0d;
if (!double.TryParse(value.ToString(), out double v))
{
return 0d;
}
int _in = (int)this.OutType;
int _out = (int)this.InType;
while (_in != _out)
{
if (_in < _out)
{
v /= 1024f;
++_in;
}
else
{
v *= 1024f;
--_in;
}
}
return v;
}
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace VIZ.Framework.Core
{
/// <summary>
/// Double 转 TimeSpan 类型
/// </summary>
public enum Double2TimeSpanConverterType
{
/// <summary>
/// 小时
/// </summary>
Hour,
/// <summary>
/// 分钟
/// </summary>
Minute,
/// <summary>
/// 秒
/// </summary>
Second,
/// <summary>
/// 毫秒
/// </summary>
Millisecond
}
/// <summary>
/// Double 转 TimeSpan 转化器
/// </summary>
public class Double2TimeSpanConverter : IValueConverter
{
/// <summary>
/// 转化类型
/// </summary>
public TimeSpan2DoubleConverterType Type { get; set; } = TimeSpan2DoubleConverterType.Second;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is double))
return TimeSpan.Zero;
double v = (double)value;
switch (this.Type)
{
case TimeSpan2DoubleConverterType.Hour:
return TimeSpan.FromHours(v);
case TimeSpan2DoubleConverterType.Minute:
return TimeSpan.FromMinutes(v);
case TimeSpan2DoubleConverterType.Second:
return TimeSpan.FromSeconds(v);
case TimeSpan2DoubleConverterType.Millisecond:
return TimeSpan.FromMilliseconds(v);
default:
return TimeSpan.Zero;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is TimeSpan))
return 0d;
TimeSpan timeSpan = (TimeSpan)value;
switch (this.Type)
{
case TimeSpan2DoubleConverterType.Hour:
return timeSpan.TotalHours;
case TimeSpan2DoubleConverterType.Minute:
return timeSpan.TotalMinutes;
case TimeSpan2DoubleConverterType.Second:
return timeSpan.TotalSeconds;
case TimeSpan2DoubleConverterType.Millisecond:
return timeSpan.TotalMilliseconds;
default:
return 0d;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace VIZ.Framework.Core
{
/// <summary>
/// TimeSpan 转 Double 类型
/// </summary>
public enum TimeSpan2DoubleConverterType
{
/// <summary>
/// 小时
/// </summary>
Hour,
/// <summary>
/// 分钟
/// </summary>
Minute,
/// <summary>
/// 秒
/// </summary>
Second,
/// <summary>
/// 毫秒
/// </summary>
Millisecond
}
/// <summary>
/// TimeSpan 转 Double 转化器
/// </summary>
public class TimeSpan2DoubleConverter : IValueConverter
{
/// <summary>
/// 转化类型
/// </summary>
public TimeSpan2DoubleConverterType Type { get; set; } = TimeSpan2DoubleConverterType.Second;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is TimeSpan))
return 0d;
TimeSpan timeSpan = (TimeSpan)value;
switch (this.Type)
{
case TimeSpan2DoubleConverterType.Hour:
return timeSpan.TotalHours;
case TimeSpan2DoubleConverterType.Minute:
return timeSpan.TotalMinutes;
case TimeSpan2DoubleConverterType.Second:
return timeSpan.TotalSeconds;
case TimeSpan2DoubleConverterType.Millisecond:
return timeSpan.TotalMilliseconds;
default:
return 0d;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is double))
return TimeSpan.Zero;
double v = (double)value;
switch (this.Type)
{
case TimeSpan2DoubleConverterType.Hour:
return TimeSpan.FromHours(v);
case TimeSpan2DoubleConverterType.Minute:
return TimeSpan.FromMinutes(v);
case TimeSpan2DoubleConverterType.Second:
return TimeSpan.FromSeconds(v);
case TimeSpan2DoubleConverterType.Millisecond:
return TimeSpan.FromMilliseconds(v);
default:
return TimeSpan.Zero;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 延时信息
/// </summary>
public class DelayInfo : IDisposable
{
/// <summary>
/// 键值
/// </summary>
public string Key { get; set; }
/// <summary>
/// 行为
/// </summary>
public Action Action { get; set; }
/// <summary>
/// 延时时间
/// </summary>
public TimeSpan DelayTime { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime BeginTime { get; set; }
/// <summary>
/// 计划执行时间
/// </summary>
public DateTime ExecuteTime { get; set; }
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
this.Action = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
namespace VIZ.Framework.Core
{
/// <summary>
/// 延时管理器
/// </summary>
public class DelayManager : IDelayManager, IDisposable
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(DelayManager));
/// <summary>
/// 缓存池
/// </summary>
private Dictionary<string, DelayInfo> Pool = new Dictionary<string, DelayInfo>(100);
/// <summary>
/// 延时线程
/// </summary>
private System.Threading.Thread Thread;
/// <summary>
/// 是否已经被释放
/// </summary>
private bool IsDisposabled = false;
public DelayManager()
{
this.Thread = new System.Threading.Thread(this.Execute);
this.Thread.Start();
}
/// <summary>
/// 延时执行
/// </summary>
/// <param name="key">键</param>
/// <param name="delaySeconds">延时秒数</param>
/// <param name="action">行为</param>
public void Wait(string key, double delaySeconds, Action action)
{
this.Wait(key, TimeSpan.FromSeconds(delaySeconds), action);
}
/// <summary>
/// 延时执行
/// </summary>
/// <param name="key">键</param>
/// <param name="delayTime">延时时间</param>
/// <param name="action">行为</param>
public void Wait(string key, TimeSpan delayTime, Action action)
{
lock (this.Pool)
{
if (this.Pool.TryGetValue(key, out DelayInfo info))
{
info.Action = action;
return;
}
info = new DelayInfo();
info.Key = key;
info.Action = action;
info.BeginTime = DateTime.Now;
info.DelayTime = delayTime;
info.ExecuteTime = info.BeginTime + info.DelayTime;
this.Pool.Add(key, info);
}
}
/// <summary>
/// 释放延时执行
/// </summary>
/// <param name="key">键</param>
public void Release(string key)
{
lock (this.Pool)
{
if (!this.Pool.TryGetValue(key, out DelayInfo info))
return;
this.Pool.Remove(key);
info.Dispose();
}
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
try
{
lock (this.Pool)
{
foreach (DelayInfo info in this.Pool.Values)
{
info.Dispose();
}
this.Pool.Clear();
}
this.IsDisposabled = true;
this.Thread = null;
}
catch (Exception ex)
{
log.Error(ex);
}
}
/// <summary>
/// 执行延时任务
/// </summary>
private void Execute()
{
while (!this.IsDisposabled)
{
lock (this.Pool)
{
DateTime now = DateTime.Now;
List<DelayInfo> removeList = new List<DelayInfo>();
foreach (DelayInfo info in this.Pool.Values)
{
if (this.IsDisposabled)
break;
if (info.ExecuteTime > now)
continue;
removeList.Add(info);
try
{
info.Action?.Invoke();
}
catch (Exception ex)
{
log.Error(ex);
}
}
foreach (DelayInfo info in removeList)
{
this.Pool.Remove(info.Key);
}
}
System.Threading.Thread.Sleep(200);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 延时管理器
/// </summary>
public interface IDelayManager : IDisposable
{
/// <summary>
/// 延时执行
/// </summary>
/// <param name="key">键</param>
/// <param name="seconds">延时秒数</param>
/// <param name="action">行为</param>
void Wait(string key, double seconds, Action action);
/// <summary>
/// 延时执行
/// </summary>
/// <param name="key">键</param>
/// <param name="duration">延时</param>
/// <param name="action">行为</param>
void Wait(string key, TimeSpan duration, Action action);
/// <summary>
/// 释放延时执行
/// </summary>
/// <param name="key">键</param>
void Release(string key);
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 枚举辅助类
/// </summary>
public static class EnumHelper
{
/// <summary>
/// 获取枚举描述信息
/// </summary>
/// <param name="value">枚举值</param>
/// <returns>配置值</returns>
public static string GetDescription(this Enum value)
{
if (value == null)
return string.Empty;
FieldInfo field = value.GetType().GetField(value.ToString());
if (field == null)
return string.Empty;
DescriptionAttribute attribute = field.GetCustomAttribute<DescriptionAttribute>(false);
if (attribute == null)
return string.Empty;
return attribute.Description;
}
}
}
using System;
using System.Collections.Generic;
using System.Windows;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 图片辅助类
/// </summary>
public partial class ImageHelper
{
/// <summary>
/// 获取自适应宽度域高度
/// </summary>
/// <param name="spcWidth">源宽度</param>
/// <param name="spcHeight">源高度</param>
/// <param name="orgWidth">目标宽度</param>
/// <param name="orgHeight">目标高度</param>
/// <param name="width">自适应后的宽度</param>
/// <param name="height">自适应后的高度</param>
public static void AdjustSize(int spcWidth, int spcHeight, int orgWidth, int orgHeight, out int width, out int height)
{
if (orgWidth <= spcWidth && orgHeight <= spcHeight)
{
// 取得比例系数
float w = spcWidth / (float)orgWidth;
float h = spcHeight / (float)orgHeight;
if (w > h)
{
height = spcHeight;
width = (int)(Math.Round(orgWidth * h));
}
else if (w < h)
{
width = spcWidth;
height = (int)(Math.Round(orgHeight * w));
}
else
{
width = spcWidth;
height = spcWidth;
}
}
else
{
// 取得比例系数
float w = orgWidth / (float)spcWidth;
float h = orgHeight / (float)spcHeight;
// 宽度比大于高度比
if (w > h)
{
width = spcWidth;
height = (int)(w >= 1 ? Math.Round(orgHeight / w) : Math.Round(orgHeight * w));
}
// 宽度比小于高度比
else if (w < h)
{
height = spcHeight;
width = (int)(h >= 1 ? Math.Round(orgWidth / h) : Math.Round(orgWidth * h));
}
// 宽度比等于高度比
else
{
width = spcWidth;
height = spcHeight;
}
}
}
/// <summary>
/// 缩放,dstWidth 和 dstHeight 只能有一个有值
/// </summary>
/// <param name="srcWidth">源宽度</param>
/// <param name="srcHeight">源高度</param>
/// <param name="dstWidth">目标宽度,高度会根据宽度值计算得出,</param>
/// <param name="dstHeight">目标高度,宽度会根据高度计算得出</param>
/// <returns></returns>
public static Rect Resize(int srcWidth, int srcHeight, int? dstWidth, int? dstHeight)
{
if (dstWidth != null && dstHeight != null)
throw new Exception("dstWidth is not null and dstHeight is not null.");
if (dstWidth == null && dstHeight == null)
throw new Exception("dstWidth is null and dstHeight is null.");
Rect result = new Rect();
float p = (float)srcWidth / srcHeight;
if (dstWidth != null)
{
result.Width = dstWidth.Value;
result.Height = dstWidth.Value / p;
}
else if (dstHeight != null)
{
result.Height = dstHeight.Value;
result.Width = dstHeight.Value * p;
}
return result;
}
/// <summary>
/// 将UI坐标点转化为图片坐标点
/// </summary>
/// <param name="imgWidth">图片宽度</param>
/// <param name="imgHeight">图片高度</param>
/// <param name="uiDrawRect">图片在UI的绘制区域</param>
/// <param name="uiPoint">UI坐标点</param>
/// <returns>图片坐标点</returns>
public static Point ConvertUiPointToImagePoint(int imgWidth, int imgHeight, Rect uiDrawRect, Point uiPoint)
{
double xp = uiDrawRect.Width / imgWidth;
double yp = uiDrawRect.Height / imgHeight;
double destX = (uiPoint.X - uiDrawRect.X) / xp;
double destY = (uiPoint.Y - uiDrawRect.Y) / yp;
return new Point(destX, destY);
}
/// <summary>
/// 将UI矩形区域转化为图片矩形区域
/// </summary>
/// <param name="imgWidth">图片宽度</param>
/// <param name="imgHeight">图片高度</param>
/// <param name="uiDrawRect">图片在UI的绘制区域</param>
/// <param name="uiRect">UI矩形区域</param>
/// <returns>图片矩形区域</returns>
public static Rect ConvertUiRectToImageRect(int imgWidth, int imgHeight, Rect uiDrawRect, Rect uiRect)
{
Rect uiRectClip = CutRectangle(uiRect, uiDrawRect);
double xp = uiDrawRect.Width / imgWidth;
double yp = uiDrawRect.Height / imgHeight;
double destX = (uiRectClip.X - uiDrawRect.Left) / xp;
double destY = (uiRectClip.Y - uiDrawRect.Top) / yp;
double destW = uiRectClip.Width / xp;
double destH = uiRectClip.Height / yp;
return new Rect(destX, destY, destW, destH);
}
/// <summary>
/// 将图片坐标点转化为UI坐标点
/// </summary>
/// <param name="imgWidth">图片宽度</param>
/// <param name="imgHeight">图片高度</param>
/// <param name="uiDrawRect">图片在UI的绘制区域</param>
/// <param name="imgPoint">图片坐标点</param>
/// <returns>UI坐标点</returns>
public static Point ConvertImagePointToUiPoint(int imgWidth, int imgHeight, Rect uiDrawRect, Rect imgPoint)
{
double xp = uiDrawRect.Width / imgWidth;
double yp = uiDrawRect.Height / imgHeight;
double destX = uiDrawRect.X + imgPoint.X * xp;
double destY = uiDrawRect.Y + imgPoint.Y * yp;
return new Point(destX, destY);
}
/// <summary>
/// 将图片矩形区域转化为UI矩形区域
/// </summary>
/// <param name="imgWidth">图片宽度</param>
/// <param name="imgHeight">图片高度</param>
/// <param name="uiDrawRect">图片在UI的绘制区域</param>
/// <param name="imgRect">图片矩形区域</param>
/// <returns>UI矩形区域</returns>
public static Rect ConvertImageRectToUiRect(int imgWidth, int imgHeight, Rect uiDrawRect, Rect imgRect)
{
double xp = uiDrawRect.Width / imgWidth;
double yp = uiDrawRect.Height / imgHeight;
double destX = uiDrawRect.X + imgRect.X * xp;
double destY = uiDrawRect.Y + imgRect.Y * yp;
double destW = imgRect.Width * xp;
double destH = imgRect.Height * yp;
return new Rect(destX, destY, destW, destH);
}
/// <summary>
/// 使用bottom矩形区域裁剪top矩形区域,使top矩形区域包括在bottom矩形区域内
/// </summary>
/// <param name="topRect">top矩形区域</param>
/// <param name="bottomRect">bottom矩形区域</param>
/// <returns>裁剪后的矩形区域</returns>
public static Rect CutRectangle(Rect topRect, Rect bottomRect)
{
double left = topRect.Left;
double right = topRect.Right;
double top = topRect.Top;
double bottom = topRect.Bottom;
// 左
if (topRect.Left < bottomRect.Left)
{
left = bottomRect.Left;
}
if (topRect.Left > bottomRect.Right)
{
left = bottomRect.Right;
}
// 上
if (topRect.Top < bottomRect.Top)
{
top = bottomRect.Top;
}
if (topRect.Top > bottomRect.Bottom)
{
top = bottomRect.Bottom;
}
// 右
if (topRect.Right > bottomRect.Right)
{
right = bottomRect.Right;
}
if (topRect.Right < bottomRect.Left)
{
right = bottomRect.Left;
}
// 下
if (topRect.Bottom < bottomRect.Top)
{
bottom = bottomRect.Top;
}
if (topRect.Bottom > bottomRect.Bottom)
{
bottom = bottomRect.Bottom;
}
return new Rect(left, top, right - left, bottom - top);
}
}
}
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace VIZ.Framework.Core
{
/// <summary>
/// 图片辅助类扩展
/// </summary>
public static class ImageHelperExpand
{
/// <summary>
/// 将RawRectangleF转化为Rect
/// </summary>
/// <param name="rect">RawRectangleF</param>
/// <returns>Rect</returns>
public static Rect ToRect(this RawRectangleF rect)
{
return new Rect(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
}
/// <summary>
/// 将Rect转化为RawRectangleF
/// </summary>
/// <param name="rect">Rect</param>
/// <returns>RawRectangleF</returns>
public static RawRectangleF ToRawRectangleF(this Rect rect)
{
return new RawRectangleF((float)rect.Left, (float)rect.Top, (float)rect.Right, (float)rect.Bottom);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 循环管理器
/// </summary>
public interface ILoopManager : IDisposable
{
/// <summary>
/// 注册
/// </summary>
/// <param name="key">键</param>
/// <param name="intervalSec">间隔(单位:秒)</param>
/// <param name="action">行为</param>
void Register(string key, double intervalSec, Action action);
/// <summary>
/// 注销
/// </summary>
/// <param name="key">键</param>
void UnRegister(string key);
/// <summary>
/// 开始
/// </summary>
void Start();
/// <summary>
/// 停止
/// </summary>
void Stop();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 循环信息
/// </summary>
public class LoopInfo
{
/// <summary>
/// 键
/// </summary>
public string Key { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime BeginTime { get; set; }
/// <summary>
/// 上一次触发时间
/// </summary>
public DateTime LastTriggerTime { get; set; }
/// <summary>
/// 等待时间
/// </summary>
public TimeSpan WaitTime { get; set; }
/// <summary>
/// 行为
/// </summary>
public Action Action { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
namespace VIZ.Framework.Core
{
/// <summary>
/// 循环管理器
/// </summary>
public class LoopManager : ILoopManager
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(LoopManager));
/// <summary>
/// 循环信息池
/// </summary>
private Dictionary<string, LoopInfo> pool = new Dictionary<string, LoopInfo>();
/// <summary>
/// 循环线程
/// </summary>
private System.Threading.Thread thread;
/// <summary>
/// 线程信息
/// </summary>
private LoopThreadInfo threadInfo;
/// <summary>
/// 注册
/// </summary>
/// <param name="key">键</param>
/// <param name="intervalSec">间隔(单位:秒)</param>
/// <param name="action">行为</param>
public void Register(string key, double intervalSec, Action action)
{
lock (this.pool)
{
LoopInfo info = new LoopInfo();
info.Key = key;
info.WaitTime = TimeSpan.FromSeconds(intervalSec);
info.BeginTime = DateTime.Now;
info.Action = action;
info.LastTriggerTime = DateTime.Now;
this.pool[key] = info;
}
}
/// <summary>
/// 注销
/// </summary>
/// <param name="key">键</param>
public void UnRegister(string key)
{
lock (this.pool)
{
if (this.pool.ContainsKey(key))
{
this.pool.Remove(key);
}
}
}
/// <summary>
/// 开始
/// </summary>
public void Start()
{
this.Stop();
this.threadInfo = new LoopThreadInfo();
this.thread = new System.Threading.Thread(this.Execute);
this.thread.IsBackground = true;
this.thread.Start();
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
if (this.threadInfo != null)
{
this.threadInfo.IsCancel = true;
}
this.threadInfo = null;
this.thread = null;
}
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this.Stop();
}
/// <summary>
/// 执行
/// </summary>
private void Execute()
{
LoopThreadInfo info = this.threadInfo;
if (info == null)
return;
while (!info.IsCancel)
{
lock (this.pool)
{
DateTime now = DateTime.Now;
foreach (LoopInfo item in this.pool.Values)
{
if (item == null)
continue;
if (now >= item.LastTriggerTime + item.WaitTime)
{
try
{
item.Action();
item.LastTriggerTime = now;
}
catch (Exception ex)
{
log.Error(ex);
}
}
}
}
System.Threading.Thread.Sleep(500);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 循环线程信息
/// </summary>
public class LoopThreadInfo
{
/// <summary>
/// 是否已经取消
/// </summary>
public bool IsCancel { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 数学辅助类
/// </summary>
public static partial class MathHelper
{
/// <summary>
/// 裁切数字
/// </summary>
/// <typeparam name="T">数字类型</typeparam>
/// <param name="min">最小值</param>
/// <param name="max">最大值</param>
/// <param name="value">当前值</param>
/// <returns>裁切后的数值</returns>
public static T Clip<T>(T min, T max, T value) where T : IComparable<T>
{
T result = value;
if (value.CompareTo(min) == -1)
{
result = min;
}
if (value.CompareTo(max) == 1)
{
result = max;
}
return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 消息接口
/// </summary>
public interface IMessageInfo : IDisposable
{
/// <summary>
/// 关联对象
/// </summary>
object Target { get; set; }
/// <summary>
/// 消息类型
/// </summary>
Type Type { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 消息管理类接口
/// </summary>
public interface IMessageManager : IDisposable
{
/// <summary>
/// 注册一个消息
/// </summary>
/// <param name="target">关联对象</param>
/// <param name="action">行为</param>
void Register<T>(object target, Action<T> action);
/// <summary>
/// 注销关联对象的消息
/// </summary>
/// <param name="target">关联对象</param>
void UnRegister(object target);
/// <summary>
/// 注销所有消息
/// </summary>
void UnRegister();
/// <summary>
/// 发送消息
/// </summary>
/// <param name="token">标志</param>
/// <param name="message">消息</param>
void Send<T>(T message);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 消息信息
/// </summary>
public class MessageInfo<T> : IMessageInfo
{
/// <summary>
/// 消息类型
/// </summary>
public Type Type { get; set; }
/// <summary>
/// 关联对象
/// </summary>
public object Target { get; set; }
/// <summary>
/// 行为
/// </summary>
public Action<T> Action { get; set; }
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this.Target = null;
this.Type = null;
this.Action = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 消息管理类
/// </summary>
public class MessageManager : IMessageManager
{
/// <summary>
/// 消息信息列表
/// </summary>
private List<IMessageInfo> list = new List<IMessageInfo>();
/// <summary>
/// 注册一个消息
/// </summary>
/// <param name="target">关联对象</param>
/// <param name="action">行为</param>
public void Register<T>(object target, Action<T> action)
{
if (target == null)
throw new ArgumentNullException("target");
if (action == null)
throw new ArgumentNullException("target");
lock (this.list)
{
MessageInfo<T> info = new MessageInfo<T>();
info.Action = action;
info.Target = target;
info.Type = typeof(T);
this.list.Add(info);
}
}
/// <summary>
/// 注销关联对象的消息
/// </summary>
/// <param name="target">关联对象</param>
public void UnRegister(object target)
{
lock (this.list)
{
for (int i = 0; i < this.list.Count; ++i)
{
IMessageInfo info = this.list[i];
if (info.Target == target)
{
this.list.RemoveAt(i);
--i;
}
}
}
}
/// <summary>
/// 注销所有消息
/// </summary>
public void UnRegister()
{
if (this.list == null)
return;
lock (this.list)
{
this.list.Clear();
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message">消息</param>
public void Send<T>(T message)
{
if (message == null)
return;
foreach (IMessageInfo i in this.list)
{
MessageInfo<T> info = i as MessageInfo<T>;
if (info == null)
continue;
info.Action(message);
}
}
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this.UnRegister();
this.list = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 监控管理器
/// </summary>
public interface IMonitorManager
{
/// <summary>
/// 添加监视任务
/// </summary>
/// <param name="task">监视任务</param>
void AppendTask(MonitorTaskBase task);
/// <summary>
/// 添加触发器
/// </summary>
/// <param name="name">任务名称</param>
/// <param name="trigger">触发器</param>
void AppendTrigger(string name, IMonitorTrigger trigger);
/// <summary>
/// 获取监视信息
/// </summary>
/// <param name="name">监视名称</param>
/// <returns>监视模型</returns>
T GetInfo<T>(string name) where T : MonitorInfolBase;
/// <summary>
/// 开始监控
/// </summary>
void Start();
/// <summary>
/// 停止监控
/// </summary>
void Stop();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 监视解释器
/// </summary>
public interface IMonitorProvider
{
/// <summary>
/// 名称
/// </summary>
string Name { get; }
/// <summary>
/// 执行
/// </summary>
/// <param name="model">监控信息</param>
void Execute(MonitorInfolBase info);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 监视器触发器
/// </summary>
public interface IMonitorTrigger
{
/// <summary>
/// 是否可以执行
/// </summary>
/// <param name="model">监视器模型</param>
/// <returns>是否可以执行</returns>
bool CanExecute(MonitorInfolBase model);
/// <summary>
/// 执行
/// </summary>
/// <param name="model">模型</param>
void Execute(MonitorInfolBase model);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 监控信息基类
/// </summary>
public abstract class MonitorInfolBase
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 监视管理器
/// </summary>
public class MonitorManager : IMonitorManager
{
/// <summary>
/// 任务列表
/// </summary>
private List<MonitorTaskBase> TaskList = new List<MonitorTaskBase>();
/// <summary>
/// 添加监视任务
/// </summary>
/// <param name="task">监视任务</param>
public void AppendTask(MonitorTaskBase task)
{
this.TaskList.Add(task);
}
/// <summary>
/// 添加触发器
/// </summary>
/// <param name="name">任务名称</param>
/// <param name="trigger">触发器</param>
public void AppendTrigger(string name, IMonitorTrigger trigger)
{
MonitorTaskBase task = this.TaskList.FirstOrDefault(p => p.Name == name);
if (task == null)
throw new Exception($"monitor: {name} not found.");
task.Triggers.Add(trigger);
}
/// <summary>
/// 获取监视信息
/// </summary>
/// <param name="name">监视名称</param>
/// <returns>监视模型</returns>
public T GetInfo<T>(string name) where T : MonitorInfolBase
{
MonitorTaskBase task = this.TaskList.FirstOrDefault(p => p.Name == name);
return task?.Info as T;
}
/// <summary>
/// 开始监控
/// </summary>
public void Start()
{
foreach (MonitorTaskBase task in this.TaskList)
{
task.Start();
}
}
/// <summary>
/// 停止监控
/// </summary>
public void Stop()
{
foreach (MonitorTaskBase task in this.TaskList)
{
task.Stop();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
namespace VIZ.Framework.Core
{
/// <summary>
/// 监视任务基类
/// </summary>
public abstract class MonitorTaskBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(MonitorTaskBase));
/// <summary>
/// 名称
/// </summary>
public abstract string Name { get; }
/// <summary>
/// 监视间隔(单位:毫秒)
/// </summary>
public abstract int Interval { get; }
/// <summary>
/// 监控信息
/// </summary>
public abstract MonitorInfolBase Info { get; }
/// <summary>
/// 触发器集合
/// </summary>
public List<IMonitorTrigger> Triggers { get; private set; } = new List<IMonitorTrigger>();
/// <summary>
/// 任务信息
/// </summary>
private MonitorTaskInfo TaskInfo;
/// <summary>
/// 执行任务
/// </summary>
private Task ExecuteTask;
/// <summary>
/// 开始
/// </summary>
public void Start()
{
MonitorTaskInfo info = new MonitorTaskInfo();
this.TaskInfo = info;
this.ExecuteTask = Task.Run(() =>
{
while (!info.IsCancel)
{
this.Execute();
this.ExecuteTrigger();
System.Threading.Thread.Sleep(this.Interval);
}
});
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
this.TaskInfo.IsCancel = true;
this.TaskInfo = null;
this.ExecuteTask = null;
}
/// <summary>
/// 执行触发器
/// </summary>
protected void ExecuteTrigger()
{
foreach (IMonitorTrigger trigger in this.Triggers)
{
try
{
if (!trigger.CanExecute(this.Info))
continue;
trigger.Execute(this.Info);
}
catch (Exception ex)
{
log.Error(ex);
}
}
}
/// <summary>
/// 执行
/// </summary>
protected abstract void Execute();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 监控任务信息
/// </summary>
public class MonitorTaskInfo
{
/// <summary>
/// 是否取消
/// </summary>
public bool IsCancel { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 监控GPU信息
/// </summary>
public class SystemMonitorGpuInfo
{
/// <summary>
/// 物理GPU编号
/// </summary>
public int Physics { get; set; }
/// <summary>
/// GPU名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 使用率
/// </summary>
public double UsedPercentage { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 系统监视信息
/// </summary>
public class SystemMonitorInfo : MonitorInfolBase
{
/// <summary>
/// CPU 利用率
/// </summary>
public double CpuUsedPercentage { get; set; }
/// <summary>
/// 内存利用率
/// </summary>
public double MemoryUsedPercentage { get; set; }
/// <summary>
/// 内存使用量
/// </summary>
public ulong MemoryUsed { get; set; }
/// <summary>
/// 内存总量
/// </summary>
public ulong MemoryTotal { get; set; }
/// <summary>
/// GPU信息集合
/// </summary>
public List<SystemMonitorGpuInfo> GpuInfos { get; set; } = new List<SystemMonitorGpuInfo>();
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 系统监视解释器 -- CPU
/// </summary>
public class SystemMonitorProvider_CPU : IMonitorProvider
{
/// <summary>
/// 名称
/// </summary>
public string Name => "CPU";
/// <summary>
/// CPU性能计数组件
/// </summary>
private PerformanceCounter cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
/// <summary>
/// 执行
/// </summary>
/// <param name="info">监控信息</param>
public void Execute(MonitorInfolBase info)
{
SystemMonitorInfo system = info as SystemMonitorInfo;
system.CpuUsedPercentage = this.cpuCounter.NextValue() / 100f;
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 系统监视解释器 -- GPU
/// </summary>
public class SystemMonitorProvider_GPU : IMonitorProvider
{
/// <summary>
/// 名称
/// </summary>
public string Name => "GPU";
/// <summary>
/// 执行
/// </summary>
/// <param name="info">监控信息</param>
public void Execute(MonitorInfolBase info)
{
SystemMonitorInfo system = info as SystemMonitorInfo;
try
{
NvAPIWrapper.NVIDIA.Initialize();
var gpus = NvAPIWrapper.GPU.PhysicalGPU.GetPhysicalGPUs();
for (int i = 0; i < gpus.Length; i++)
{
SystemMonitorGpuInfo item = system.GpuInfos.FirstOrDefault(p => p.Physics == i);
if (item == null)
{
item = new SystemMonitorGpuInfo();
item.Physics = i;
item.Name = gpus[i].FullName;
system.GpuInfos.Add(item);
}
item.UsedPercentage = gpus[i].UsageInformation.GPU.Percentage / 100d;
}
}
catch
{
// 无需处理异常
}
finally
{
NvAPIWrapper.NVIDIA.Unload();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 系统监视解释器 -- 内存
/// </summary>
public class SystemMonitorProvider_Memory : IMonitorProvider
{
/// <summary>
/// 名称
/// </summary>
public string Name => "Memory";
/// <summary>
/// 执行
/// </summary>
/// <param name="info">监控信息</param>
public void Execute(MonitorInfolBase info)
{
SystemMonitorInfo system = info as SystemMonitorInfo;
Microsoft.VisualBasic.Devices.ComputerInfo computer = new Microsoft.VisualBasic.Devices.ComputerInfo();
system.MemoryTotal = computer.TotalPhysicalMemory;
system.MemoryUsed = system.MemoryTotal - computer.AvailablePhysicalMemory;
system.MemoryUsedPercentage = (double)system.MemoryUsed / system.MemoryTotal;
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
namespace VIZ.Framework.Core
{
/// <summary>
/// 系统监控
/// </summary>
public class SystemMonitorTask : MonitorTaskBase
{
/// <summary>
/// 日志
/// </summary>
private ILog log = LogManager.GetLogger(typeof(SystemMonitorTask));
public SystemMonitorTask()
{
// CPU
this.providers.Add(new SystemMonitorProvider_CPU());
// 内存
this.providers.Add(new SystemMonitorProvider_Memory());
// GPU
this.providers.Add(new SystemMonitorProvider_GPU());
}
/// <summary>
/// 监视名称
/// </summary>
public override string Name => "System";
/// <summary>
/// 监视间隔(单位:毫秒)
/// </summary>
public override int Interval => 1000;
/// <summary>
/// 监视模型
/// </summary>
public override MonitorInfolBase Info => info;
/// <summary>
/// 模型
/// </summary>
private SystemMonitorInfo info = new SystemMonitorInfo();
/// <summary>
/// 监视器解释器集合
/// </summary>
private List<IMonitorProvider> providers = new List<IMonitorProvider>();
/// <summary>
/// 执行监视
/// </summary>
protected override void Execute()
{
foreach (IMonitorProvider provider in this.providers)
{
try
{
provider.Execute(this.info);
}
catch (Exception ex)
{
log.Error(ex);
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 网络辅助类
/// </summary>
public static class NetHelper
{
/// summary
/// 获取网卡硬件地址
/// /summary
/// returns mac地址 /returns
public static string GetMacAddress()
{
try
{
//获取网卡硬件地址
string mac = string.Empty;
ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
if ((bool)mo["IPEnabled"])
{
mac = mo["MacAddress"].ToString();
break;
}
}
moc.Dispose();
mc.Dispose();
moc = null;
mc = null;
return mac;
}
catch
{
return string.Empty;
}
}
/// <summary>
/// 获取一个可用的UDP端口
/// </summary>
/// <param name="startPort">开始端口</param>
/// <param name="endPort">结束端口</param>
/// <param name="notIn">端口不应该再该列表中</param>
/// <returns>可用的UDP端口</returns>
public static int GetAvailableUdpPort(int startPort, int endPort, List<int> notIn)
{
//提供本地计算机有关网络连接信息
IPGlobalProperties iPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
//获取可用的UDP监听终结点信息
IPEndPoint[] iPEndPoints = iPGlobalProperties.GetActiveUdpListeners();
for (int port = startPort; port <= endPort; port++)
{
if (notIn != null && notIn.Contains(port))
continue;
if (iPEndPoints.Any(p => p.Port == port))
continue;
return port;
}
return 0;
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("VIZ.Framework.Core")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.Core")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("75b39591-4bc3-4b09-bd7d-ec9f67efa96e")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// RawRectangleF 扩展
/// </summary>
public static class RawRectangleFExpand
{
/// <summary>
/// 将框剪切至视频帧的范围内
/// </summary>
/// <param name="rect">要裁切的区域</param>
/// <param name="minX">最小X值</param>
/// <param name="minY">最小Y值</param>
/// <param name="maxX">最大X值</param>
/// <param name="maxY">最大Y值</param>
/// <returns>是否成功裁切</returns>
public static RawRectangleF ClipInVideoFrame(RawRectangleF rect, float minX, float minY, float maxX, float maxY)
{
rect.Left = MathHelper.Clip(minX, maxX, rect.Left);
rect.Right = MathHelper.Clip(minX, maxX, rect.Right);
rect.Top = MathHelper.Clip(minY, maxY, rect.Top);
rect.Bottom = MathHelper.Clip(minY, maxY, rect.Bottom);
return rect;
}
/// <summary>
/// 区域是否有效
/// </summary>
/// <param name="rect">矩形区域</param>
/// <returns>是否有效</returns>
public static bool IsEffective(RawRectangleF rect)
{
if (rect.Left >= rect.Right || rect.Top >= rect.Bottom)
return false;
return true;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX.Mathematics.Interop;
namespace VIZ.Framework.Core
{
/// <summary>
/// SharpDX颜色辅助类
/// </summary>
public static class SharpDxColorHelper
{
/// <summary>
/// 由RGBG值获取颜色
/// </summary>
/// <param name="r">红色值</param>
/// <param name="g">绿色值</param>
/// <param name="b">蓝色值</param>
/// <param name="a">透明度</param>
/// <returns>颜色</returns>
public static RawColor4 FromRGBA(float r, float g, float b, float a)
{
return new RawColor4(r, g, b, a);
}
/// <summary>
/// 由RGBG值获取颜色
/// </summary>
/// <param name="r">红色值</param>
/// <param name="g">绿色值</param>
/// <param name="b">蓝色值</param>
/// <param name="a">透明度</param>
/// <returns>颜色</returns>
public static RawColor4 FromRGBA(double r, double g, double b, double a)
{
return new RawColor4((float)r, (float)g, (float)b, (float)a);
}
/// <summary>
/// 由RGBG值获取颜色
/// </summary>
/// <param name="code">颜色码(#AARRGGBB),例如:#FFFF0000</param>
/// <returns>颜色</returns>
public static RawColor4 FromString(string code)
{
RawColor4 result = new RawColor4();
result.A = Convert.ToInt32(code.Substring(1, 2), 16) / 255f;
result.R = Convert.ToInt32(code.Substring(3, 2), 16) / 255f;
result.G = Convert.ToInt32(code.Substring(5, 2), 16) / 255f;
result.B = Convert.ToInt32(code.Substring(7, 2), 16) / 255f;
return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TDx.SpaceMouse.Navigation3D;
namespace VIZ.Framework.Core
{
/// <summary>
/// 3D鼠标摄像机
/// </summary>
public class Navigation3DCamera
{
/// <summary>
/// 位置矩阵
/// </summary>
public Matrix Matrix { get; internal set; } = new Matrix(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 30, 1);
/// <summary>
/// 上方向
/// </summary>
public Vector UpDirection { get; internal set; } = new Vector(0, 1, 0);
/// <summary>
/// 面向
/// </summary>
public Vector LookDirection { get; internal set; } = new Vector(0, 0, -1);
/// <summary>
/// 位置
/// </summary>
public Point Position { get; internal set; } = new Point(0, 0, 30);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TDx.SpaceMouse.Navigation3D;
namespace VIZ.Framework.Core
{
/// <summary>
/// 3D鼠标管理器
/// </summary>
public static class Navigation3DManager
{
/// <summary>
/// 3D鼠标模型
/// </summary>
public static Navigation3DModel Navigation3DModel { get; private set; }
/// <summary>
/// 3D鼠标
/// </summary>
public static Navigation3D Navigation3D { get; private set; }
/// <summary>
/// 初始化
/// </summary>
/// <param name="profileName">3D鼠标配置名称</param>
/// <param name="maxX">X偏移量最大值</param>
public static void Init(string profileName, double maxX)
{
Navigation3DModel = new Navigation3DModel();
Navigation3DModel.MaxX = maxX;
Navigation3D = new Navigation3D(Navigation3DModel);
Navigation3D.FrameTiming = Navigation3D.TimingSource.SpaceMouse;
Navigation3D.Open3DMouse(profileName);
}
/// <summary>
/// 销毁
/// </summary>
public static void Dispose()
{
Navigation3D?.Close();
Navigation3DModel = null;
Navigation3D = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TDx.SpaceMouse.Navigation3D;
namespace VIZ.Framework.Core
{
/// <summary>
/// 3D鼠标模型 INavigation
/// </summary>
public partial class Navigation3DModel : INavigation3D
{
public Matrix GetCameraMatrix()
{
#if DEBUG
Debug.WriteLine("GetCameraMatrix");
#endif
return this.Camera.Matrix;
}
public Point GetCameraTarget()
{
#if DEBUG
Debug.WriteLine("GetCameraTarget");
#endif
return this.Camera.Position;
}
public Matrix GetCoordinateSystem()
{
#if DEBUG
Debug.WriteLine("GetCoordinateSystem");
#endif
return Matrix.Identity;
}
public Matrix GetFrontView()
{
#if DEBUG
Debug.WriteLine("GetFrontView");
#endif
return Matrix.Identity;
}
public Point GetLookAt()
{
#if DEBUG
Debug.WriteLine("GetLookAt");
#endif
return new Point(0, 0, -1);
}
public Box GetModelExtents()
{
#if DEBUG
Debug.WriteLine("GetModelExtents");
#endif
return new Box(-1, -1, 0, 1, 1, 0);
}
public Point GetPivotPosition()
{
#if DEBUG
Debug.WriteLine("GetPivotPosition");
#endif
return new Point();
}
public Point GetPointerPosition()
{
#if DEBUG
Debug.WriteLine("GetPointerPosition");
#endif
return new Point();
}
public Box GetSelectionExtents()
{
#if DEBUG
Debug.WriteLine("GetSelectionExtents");
#endif
return new Box(-1, -1, 0, 1, 1, 0);
}
public Matrix GetSelectionTransform()
{
#if DEBUG
Debug.WriteLine("GetSelectionTransform");
#endif
return Matrix.Identity;
}
public Plane GetViewConstructionPlane()
{
#if DEBUG
Debug.WriteLine("GetViewConstructionPlane");
#endif
return new Plane();
}
public Box GetViewExtents()
{
#if DEBUG
Debug.WriteLine("GetViewExtents");
#endif
return new Box(-100, -100, 0, 100, 100, 0);
}
public double GetViewFOV()
{
#if DEBUG
Debug.WriteLine("GetViewFOV");
#endif
return 45;
}
public Frustum GetViewFrustum()
{
#if DEBUG
Debug.WriteLine("GetViewFrustum");
#endif
return new Frustum(-0.00041, 0.00041, -0.00034, 0.00034, 0.01, 1000);
}
public bool IsSelectionEmpty()
{
#if DEBUG
Debug.WriteLine("IsSelectionEmpty");
#endif
return true;
}
public bool IsUserPivot()
{
#if DEBUG
Debug.WriteLine("IsUserPivot");
#endif
return false;
}
public bool IsViewPerspective()
{
#if DEBUG
Debug.WriteLine("IsViewPerspective");
#endif
return true;
}
public bool IsViewRotatable()
{
#if DEBUG
Debug.WriteLine("IsViewRotatable");
#endif
return false;
}
public void SetCameraMatrix(Matrix matrix)
{
#if DEBUG
Debug.WriteLine("SetCameraMatrix");
#endif
matrix.M41 = MathHelper.Clip(-this.MaxX, this.MaxX, matrix.M41);
this.Camera.Matrix = matrix;
this.Camera.Position = new Point(matrix.M41, matrix.M42, matrix.M43);
#if DEBUG
Debug.WriteLine($"({matrix.M41}, {matrix.M42})");
#endif
}
public void SetCameraTarget(Point target)
{
#if DEBUG
Debug.WriteLine("SetCameraTarget");
#endif
}
public void SetLookAperture(double aperture)
{
#if DEBUG
Debug.WriteLine("SetLookAperture");
#endif
}
public void SetLookDirection(Vector direction)
{
#if DEBUG
Debug.WriteLine("SetLookDirection");
#endif
}
public void SetLookFrom(Point eye)
{
#if DEBUG
Debug.WriteLine("SetLookFrom");
#endif
}
public void SetPivotPosition(Point position)
{
#if DEBUG
Debug.WriteLine("SetPivotPosition");
#endif
}
public void SetPivotVisible(bool visible)
{
#if DEBUG
Debug.WriteLine("SetPivotVisible");
#endif
}
public void SetPointerPosition(Point position)
{
#if DEBUG
Debug.WriteLine("SetPointerPosition");
#endif
}
public void SetSelectionOnly(bool onlySelection)
{
#if DEBUG
Debug.WriteLine("SetSelectionOnly");
#endif
}
public void SetSelectionTransform(Matrix matrix)
{
#if DEBUG
Debug.WriteLine("SetSelectionTransform");
#endif
}
public void SetViewExtents(Box extents)
{
#if DEBUG
Debug.WriteLine("SetViewExtents");
#endif
}
public void SetViewFOV(double fov)
{
#if DEBUG
Debug.WriteLine("SetViewFOV");
#endif
}
public void SetViewFrustum(Frustum frustum)
{
#if DEBUG
Debug.WriteLine("SetViewFrustum");
#endif
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TDx.SpaceMouse.Navigation3D;
namespace VIZ.Framework.Core
{
/// <summary>
/// 3D鼠标模型
/// </summary>
public partial class Navigation3DModel
{
/// <summary>
/// 3D鼠标模型
/// </summary>
public Navigation3DModel()
{
this.Smooth.Init(0);
}
/// <summary>
/// 摄像机
/// </summary>
public Navigation3DCamera Camera { get; private set; } = new Navigation3DCamera();
/// <summary>
/// 调匀摄像机
/// </summary>
public Navigation3DCamera SmoothCamera { get; private set; } = new Navigation3DCamera();
/// <summary>
/// 摄像机X轴最大值
/// </summary>
public double MaxX { get; set; } = 3;
/// <summary>
/// 平滑处理器
/// </summary>
private Navigation3DSmooth Smooth = new Navigation3DSmooth();
/// <summary>
/// 更新调匀值
/// </summary>
public void UpdateSmooth()
{
double x = this.Smooth.Call(-this.Camera.Position.X);
x = MathHelper.Clip(-this.MaxX, this.MaxX, x);
this.SmoothCamera.Position = new Point(x, 0, 0);
}
/// <summary>
/// 重置X值
/// </summary>
/// <param name="x">X坐标</param>
public void Reset(double x)
{
this.Camera.Position = new Point(-x, 0, 0);
this.Camera.Matrix = new Matrix(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
-x, 0, 30, 1);
this.Smooth.Init(x);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 3D鼠标平滑
/// </summary>
public class Navigation3DSmooth
{
private double min_cutoff;
private double beta;
private double d_cutoff;
private double x_prev;
private double dx_prev;
/// <summary>
/// 初始化
/// </summary>
/// <param name="x0">开始值</param>
/// <param name="dx0">之前的X值</param>
/// <param name="min_cutoff">终止值</param>
/// <param name="beta"></param>
/// <param name="d_cutoff"></param>
public void Init(double x0, double dx0 = 0, double min_cutoff = 0.015, double beta = 0, double d_cutoff = 1)
{
this.min_cutoff = min_cutoff;
this.beta = beta;
this.d_cutoff = d_cutoff;
this.x_prev = x0;
this.dx_prev = dx0;
}
/// <summary>
/// 根据实际值获取平滑值
/// </summary>
/// <param name="x">实际值</param>
/// <returns>平滑后的值</returns>
public double Call(double x)
{
double t_e = 1;
double a_d = smoothing_factor(t_e, this.d_cutoff);
double dx = (x - this.x_prev) / t_e;
double dx_hat = exponential_smoothing(a_d, dx, this.x_prev);
double cutoff = this.min_cutoff + this.beta * Math.Abs(dx_hat);
double a = smoothing_factor(t_e, cutoff);
double x_hat = exponential_smoothing(a, x, this.x_prev);
this.x_prev = x_hat;
this.dx_prev = dx_hat;
return x_hat;
}
private double smoothing_factor(double t_e, double cutoff)
{
double r = 2 * Math.PI * cutoff * t_e;
return r;
}
private double exponential_smoothing(double a, double x, double x_prev)
{
return a * x + (1 - a) * x_prev;
}
}
}
<?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>{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VIZ.Framework.Core</RootNamespace>
<AssemblyName>VIZ.Framework.Core</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=2.0.14.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.14\lib\net45\log4net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="NvAPIWrapper, Version=0.8.1.100, Culture=neutral, PublicKeyToken=310fd07b25df79b3, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\NvAPIWrapper.Net.0.8.1.101\lib\net45\NvAPIWrapper.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="ReachFramework" />
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Mathematics, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Web" />
<Reference Include="System.Windows" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="TDx.SpaceMouse.Navigation3D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d44b2a5182364560, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\05-Lib\TDx.SpaceMouse.Navigation3D.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Converter\Bool2BoolConverter.cs" />
<Compile Include="Converter\ByteSizeConverter.cs" />
<Compile Include="Enum\EnumHelper.cs" />
<Compile Include="Image\ImageHelperExpand.cs" />
<Compile Include="Image\ImageHelper.cs" />
<Compile Include="Converter\Bitmap2ImageSourceConverter.cs" />
<Compile Include="Converter\Bool2VisibilityConverter.cs" />
<Compile Include="Converter\Double2TimeSpanConverter.cs" />
<Compile Include="Converter\TimeSpan2DoubleConverter.cs" />
<Compile Include="Delay\IDelayManager.cs" />
<Compile Include="Delay\DelayInfo.cs" />
<Compile Include="Delay\DelayManager.cs" />
<Compile Include="Loop\ILoopManager.cs" />
<Compile Include="Loop\LoopInfo.cs" />
<Compile Include="Loop\LoopManager.cs" />
<Compile Include="Loop\LoopThreadInfo.cs" />
<Compile Include="Math\MathHelper.cs" />
<Compile Include="Message\IMessageInfo.cs" />
<Compile Include="Message\IMessageManager.cs" />
<Compile Include="Message\MessageInfo.cs" />
<Compile Include="Message\MessageManager.cs" />
<Compile Include="Monitor\IMonitorManager.cs" />
<Compile Include="Monitor\IMonitorProvider.cs" />
<Compile Include="Monitor\IMonitorTrigger.cs" />
<Compile Include="Monitor\MonitorManager.cs" />
<Compile Include="Monitor\MonitorInfolBase.cs" />
<Compile Include="Monitor\MonitorTaskBase.cs" />
<Compile Include="Monitor\MonitorTaskInfo.cs" />
<Compile Include="Monitor\System\Info\SystemMonitorGpuInfo.cs" />
<Compile Include="Monitor\System\Provider\SystemMonitorProvider_GPU.cs" />
<Compile Include="Monitor\System\Provider\SystemMonitorProvider_CPU.cs" />
<Compile Include="Monitor\System\Provider\SystemMonitorProvider_Memory.cs" />
<Compile Include="Monitor\System\Info\SystemMonitorInfo.cs" />
<Compile Include="Monitor\System\SystemMonitorTask.cs" />
<Compile Include="Net\NetHelper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SharpDx\RawRectangleFExpand.cs" />
<Compile Include="SharpDx\SharpDxColorHelper.cs" />
<Compile Include="ThreeDMouse\Navigation3DCamera.cs" />
<Compile Include="ThreeDMouse\Navigation3DManager.cs" />
<Compile Include="ThreeDMouse\Navigation3DModel.cs" />
<Compile Include="ThreeDMouse\Navigation3DModel.INavigation.cs" />
<Compile Include="ThreeDMouse\Navigation3DSmooth.cs" />
<Compile Include="Winform\WinformHelper.cs" />
<Compile Include="WPF\IService.cs" />
<Compile Include="WPF\IServiceManager.cs" />
<Compile Include="WPF\ModelBase.cs" />
<Compile Include="WPF\VCommand.cs" />
<Compile Include="WPF\ViewModelBase.cs" />
<Compile Include="WPF\ServiceManager.cs" />
<Compile Include="WPF\WPFHelper.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 服务
/// </summary>
public interface IService
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 服务管理
/// </summary>
public interface IServiceManager
{
/// <summary>
/// 添加图模型服务
/// </summary>
/// <param name="key">键</param>
/// <param name="service">图模型服务</param>
void AddService<T>(string key, T service) where T : class, IService;
/// <summary>
/// 移除视图模型服务
/// </summary>
/// <typeparam name="T">图模型服务类型</typeparam>
/// <param name="key">服务键</param>
void RemoveService<T>(string key) where T : class, IService;
/// <summary>
/// 获取图模型服务
/// </summary>
/// <typeparam name="T">图模型服务类型</typeparam>
/// <param name="key">服务键</param>
/// <returns>图模型服务</returns>
T GetService<T>(string key) where T : class, IService;
/// <summary>
/// 获取视图模型服务
/// </summary>
/// <typeparam name="T">图模型服务类型</typeparam>
/// <returns>图模型服务列表</returns>
List<T> GetServiceList<T>() where T : class, IService;
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 模型基类
/// </summary>
public abstract class ModelBase : INotifyPropertyChanged, INotifyPropertyChanging
{
/// <summary>
/// 属性改变前事件
/// </summary>
public event PropertyChangingEventHandler PropertyChanging;
/// <summary>
/// 属性改变后事件
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// 触发属性改变前事件
/// </summary>
/// <param name="propertyName">属性名</param>
public void RaisePropertyChanging(string propertyName)
{
this.PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
}
/// <summary>
/// 触发属性改变后事件
/// </summary>
/// <param name="propertyName">属性名</param>
public void RaisePropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Core
{
/// <summary>
/// 服务管理器
/// </summary>
public class ServiceManager : IServiceManager
{
/// <summary>
/// 图模型服务列表
/// </summary>
private Dictionary<string, IService> services = new Dictionary<string, IService>();
/// <summary>
/// 添加图模型服务
/// </summary>
/// <param name="key">键</param>
/// <param name="service">图模型服务</param>
public void AddService<T>(string key, T service) where T : class, IService
{
lock (this.services)
{
if (this.services.ContainsKey(key))
throw new Exception($"service key: {key}, is already exists");
this.services.Add(key, service);
}
}
/// <summary>
/// 移除视图模型服务
/// </summary>
/// <param name="key">服务键</param>
/// <typeparam name="T">图模型服务类型</typeparam>
public void RemoveService<T>(string key) where T : class, IService
{
lock (this.services)
{
if (this.services.ContainsKey(key))
{
this.services.Remove(key);
}
}
}
/// <summary>
/// 获取图模型服务
/// </summary>
/// <typeparam name="T">图模型服务类型</typeparam>
/// <param name="key">服务键</param>
/// <returns>图模型服务</returns>
public T GetService<T>(string key) where T : class, IService
{
if (!this.services.TryGetValue(key, out IService service))
return default;
return service as T;
}
/// <summary>
/// 获取视图模型服务列表
/// </summary>
/// <typeparam name="T">图模型服务类型</typeparam>
/// <returns>图模型服务列表</returns>
public List<T> GetServiceList<T>() where T : class, IService
{
return this.services.Values.Where(p => p is T).Select(p => p as T).ToList();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using log4net;
namespace VIZ.Framework.Core
{
/// <summary>
/// 命令
/// </summary>
public class VCommand : ICommand, IDisposable
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(VCommand));
/// <summary>
/// 命令
/// </summary>
/// <param name="execute">执行命令</param>
public VCommand(Action execute)
{
this._Execute = execute;
}
/// <summary>
/// 命令
/// </summary>
/// <param name="execute">执行命令</param>
/// <param name="canExecute">是否可以执行命令</param>
public VCommand(Action execute, Func<bool> canExecute)
{
this._Execute = execute;
this._CanExecute = canExecute;
}
/// <summary>
/// 是否可以执行改变时触发
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (this._CanExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if (this._CanExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
/// <summary>
/// 通知界面是否可以执行命令
/// </summary>
public void RaiseCanExecute()
{
CommandManager.InvalidateRequerySuggested();
}
/// <summary>
/// 是否可以执行命令
/// </summary>
/// <param name="parameter">参数</param>
/// <returns>是否可以执行</returns>
public bool CanExecute(object parameter)
{
try
{
if (this._CanExecute == null)
{
return true;
}
bool result = this._CanExecute();
return result;
}
catch (Exception ex)
{
log.Error(ex);
return false;
}
}
/// <summary>
/// 执行命令
/// </summary>
/// <param name="parameter">参数</param>
public void Execute(object parameter)
{
try
{
if (this._Execute == null)
return;
this._Execute();
}
catch (Exception ex)
{
log.Error(ex);
}
}
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this._CanExecute = null;
this._Execute = null;
}
/// <summary>
/// 行为
/// </summary>
private Action _Execute;
/// <summary>
/// 是否可以执行行为
/// </summary>
private Func<bool> _CanExecute;
}
/// <summary>
/// 命令
/// </summary>
/// <typeparam name="T">命令参数类型</typeparam>
public class VCommand<T> : ICommand, IDisposable
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(VCommand<T>));
/// <summary>
/// 命令
/// </summary>
/// <param name="execute">执行命令</param>
public VCommand(Action<T> execute)
{
this._Execute = execute;
}
/// <summary>
/// 命令
/// </summary>
/// <param name="execute">执行命令</param>
/// <param name="canExecute">是否可以执行命令</param>
public VCommand(Action<T> execute, Func<T, bool> canExecute)
{
this._Execute = execute;
this._CanExecute = canExecute;
}
/// <summary>
/// 是否可以执行改变时触发
/// </summary>
public event EventHandler CanExecuteChanged;
/// <summary>
/// 通知界面是否可以执行命令
/// </summary>
public void RaiseCanExecute()
{
if (this.CanExecuteChanged != null)
{
this.CanExecuteChanged(this, new EventArgs());
}
}
/// <summary>
/// 是否可以执行命令
/// </summary>
/// <param name="parameter">参数</param>
/// <returns>是否可以执行</returns>
public bool CanExecute(object parameter)
{
try
{
if (this._CanExecute == null)
{
return true;
}
bool result = this._CanExecute((T)parameter);
return result;
}
catch (Exception ex)
{
log.Error(ex);
return false;
}
}
/// <summary>
/// 执行命令
/// </summary>
/// <param name="parameter">参数</param>
public void Execute(object parameter)
{
try
{
if (this._Execute == null)
return;
this._Execute((T)parameter);
}
catch (Exception ex)
{
log.Error(ex);
}
}
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this._CanExecute = null;
this._Execute = null;
}
/// <summary>
/// 行为
/// </summary>
private Action<T> _Execute;
/// <summary>
/// 是否可以执行行为
/// </summary>
private Func<T, bool> _CanExecute;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace VIZ.Framework.Core
{
/// <summary>
/// 视图模型基类
/// </summary>
public abstract class ViewModelBase : ModelBase
{
/// <summary>
/// 视图
/// </summary>
public WeakReference<FrameworkElement> View { get; protected set; }
/// <summary>
/// 是否已经完成加载
/// </summary>
protected bool IsAlreadyLoaded;
/// <summary>
/// 获取视图
/// </summary>
/// <typeparam name="T">视图类型</typeparam>
/// <returns>视图</returns>
public T GetView<T>() where T : FrameworkElement
{
if (this.View == null)
return null;
if (!this.View.TryGetTarget(out FrameworkElement view))
return null;
return view as T;
}
/// <summary>
/// 获取窗口
/// </summary>
/// <returns>窗口</returns>
public Window GetWindow()
{
FrameworkElement view = this.GetView<FrameworkElement>();
if (view == null)
return null;
Window window = WPFHelper.GetAncestorByType<Window>(view);
return window;
}
/// <summary>
/// 设置视图
/// </summary>
/// <param name="view">视图</param>
public void SetView(FrameworkElement view)
{
this.View = new WeakReference<FrameworkElement>(view);
}
}
}
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.Threading;
using log4net;
namespace VIZ.Framework.Core
{
/// <summary>
/// WPF辅助类
/// </summary>
public static class WPFHelper
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(WPFHelper));
/// <summary>
/// 当前是否处于设计模式
/// </summary>
/// <param name="control">控件</param>
/// <returns>是否处于设计模式</returns>
public static bool IsInDesignMode(DependencyObject control)
{
return System.ComponentModel.DesignerProperties.GetIsInDesignMode(control);
}
/// <summary>
/// 绑定视图模型
/// </summary>
/// <param name="view">视图</param>
/// <param name="vm">视图模型</param>
public static void BindingViewModel(FrameworkElement view, ViewModelBase vm)
{
vm.SetView(view);
view.DataContext = vm;
}
#region VisualTreeHelper -- 视觉树帮助
/// <summary>
/// 查找父级控件
/// </summary>
/// <typeparam name="T">要查找的父级控件类型</typeparam>
/// <param name="element">查找的开始控件</param>
/// <returns>查找结果</returns>
public static T FindParent<T>(FrameworkElement element) where T : class
{
for (FrameworkElement e = element.TemplatedParent as FrameworkElement; e != null; e = e.TemplatedParent as FrameworkElement)
{
T local = e as T;
if (local != null)
return local;
}
return default(T);
}
/// <summary>
/// 查找父级控件
/// </summary>
/// <param name="type">父元素类型</param>
/// <param name="element">查找的开始控件</param>
/// <returns>查找结果</returns>
public static object FindParent(FrameworkElement element, Type type)
{
for (FrameworkElement e = element.TemplatedParent as FrameworkElement; e != null; e = e.TemplatedParent as FrameworkElement)
{
if (e.GetType().Equals(type))
return e;
}
return null;
}
/// <summary>
/// 使用可视化树查找父级控件
/// </summary>
/// <typeparam name="T">要查找的控件类型</typeparam>
/// <param name="element">查找的开始控件</param>
/// <returns>查找结果</returns>
public static T GetAncestorByType<T>(DependencyObject element) where T : class
{
if (element == null)
return default(T);
if (element is T)
return element as T;
return GetAncestorByType<T>(System.Windows.Media.VisualTreeHelper.GetParent(element));
}
/// <summary>
/// 使用可视化树查找父级控件
/// </summary>
/// <param name="type">父元素类型</param>
/// <param name="element">查找的开始控件</param>
/// <returns>查找结果</returns>
public static object GetAncestorByType(DependencyObject element, Type type)
{
if (element == null)
return null;
if (element.GetType().Equals(type))
return element;
return GetAncestorByType(System.Windows.Media.VisualTreeHelper.GetParent(element), type);
}
#endregion
#region UIThread -- UI线程
/// <summary>
/// 开始安全的UI同步更新
/// </summary>
/// <param name="action">行为</param>
/// <param name="dispatcherPriority">优先级</param>
public static void Invoke(Action action, DispatcherPriority dispatcherPriority = DispatcherPriority.Render)
{
Application.Current?.Dispatcher?.Invoke(new EventHandler<EventArgs>((o, e) =>
{
try
{
action();
}
catch (Exception ex)
{
log.Error(ex);
}
}), dispatcherPriority, null, null);
}
/// <summary>
/// 开始安全的UI同步更新
/// </summary>
/// <param name="action">行为</param>
/// <param name="dispatcherPriority">优先级</param>
public static void BeginInvoke(Action action, DispatcherPriority dispatcherPriority = DispatcherPriority.Render)
{
Application.Current?.Dispatcher?.BeginInvoke(new EventHandler<EventArgs>((o, e) =>
{
try
{
action();
}
catch (Exception ex)
{
log.Error(ex);
}
}), dispatcherPriority, null, null);
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
namespace VIZ.Framework.Core
{
/// <summary>
/// Winform辅助类
/// </summary>
public static class WinformHelper
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(WinformHelper));
/// <summary>
/// 是否是处于设计模式
/// </summary>
/// <returns>是否是处于设计模式</returns>
public static bool IsInDesignMode()
{
bool returnFlag = false;
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
{
returnFlag = true;
}
else if (Process.GetCurrentProcess().ProcessName == "devenv")
{
returnFlag = true;
}
return returnFlag;
}
/// <summary>
/// 如果需要在UI线程执行,那么切换至UI线程同步执行
/// </summary>
/// <param name="control">控件</param>
/// <param name="action">方法</param>
public static void InvokeOnUiThreadIfRequired(System.Windows.Forms.Control control, Action action)
{
try
{
if (control.IsDisposed)
return;
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action.Invoke();
}
}
catch (Exception ex)
{
log.Error(ex);
}
}
/// <summary>
/// 如果需要在UI线程执行,那么切换至UI线程稍后执行
/// </summary>
/// <param name="control">控件</param>
/// <param name="action">方法</param>
public static void BeginInvkoeOnUiTrheadIfRequired(System.Windows.Forms.Control control, Action action)
{
try
{
if (control.IsDisposed)
return;
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
action.Invoke();
}
}
catch (Exception ex)
{
log.Error(ex);
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.14" targetFramework="net48" />
<package id="NvAPIWrapper.Net" version="0.8.1.101" targetFramework="net48" />
<package id="SharpDX" version="4.2.0" targetFramework="net48" />
<package id="SharpDX.Mathematics" version="4.2.0" targetFramework="net48" />
</packages>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using VIZ.Framework.Storage;
namespace VIZ.Framework.Domain
{
/// <summary>
/// 应用程序域
/// </summary>
public class ApplicationDomain
{
protected ApplicationDomain() { }
/// <summary>
/// INI 仓储
/// </summary>
public static IniStorage IniStorage { get; private set; } = new IniStorage(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "config.ini"));
/// <summary>
/// 消息管理器
/// </summary>
public static IMessageManager MessageManager { get; private set; } = new MessageManager();
/// <summary>
/// 延时管理器
/// </summary>
public static IDelayManager DelayManager { get; private set; } = new DelayManager();
/// <summary>
/// 服务管理器
/// </summary>
public static IServiceManager ServiceManager { get; private set; } = new ServiceManager();
/// <summary>
/// 循环管理器
/// </summary>
public static ILoopManager LoopManager { get; private set; } = new LoopManager();
/// <summary>
/// 监控管理器
/// </summary>
public static IMonitorManager MonitorManager { get; private set; } = new MonitorManager();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Domain
{
/// <summary>
/// UDP控制台消息
/// </summary>
public class UdpConsoleMessage
{
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 该消息是否是发送消息,否则为接收到的消息
/// </summary>
public bool IsSender { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
namespace VIZ.Framework.Domain
{
/// <summary>
/// 系统监控GPU模型
/// </summary>
public class SystemMonitorGpuModel : ModelBase
{
#region Physics -- 物理GPU编号
private int physics;
/// <summary>
/// 物理GPU编号
/// </summary>
public int Physics
{
get { return physics; }
set { physics = value; this.RaisePropertyChanged(nameof(Physics)); }
}
#endregion
#region UsedPercentage -- 使用率
private double usedPercentage;
/// <summary>
/// 使用率
/// </summary>
public double UsedPercentage
{
get { return usedPercentage; }
set { usedPercentage = value; this.RaisePropertyChanged(nameof(UsedPercentage)); }
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
namespace VIZ.Framework.Domain
{
/// <summary>
/// 系统监控模型
/// </summary>
public class SystemMonitorModel : ModelBase
{
#region CpuUsedPercentage -- CPU 利用率
private double cpuUsedPercentage;
/// <summary>
/// CPU 利用率
/// </summary>
public double CpuUsedPercentage
{
get { return cpuUsedPercentage; }
set { cpuUsedPercentage = value; this.RaisePropertyChanged(nameof(CpuUsedPercentage)); }
}
#endregion
#region MemoryUsedPercentage -- 内存利用率
private double memoryUsedPercentage;
/// <summary>
/// 内存利用率
/// </summary>
public double MemoryUsedPercentage
{
get { return memoryUsedPercentage; }
set { memoryUsedPercentage = value; this.RaisePropertyChanged(nameof(MemoryUsedPercentage)); }
}
#endregion
#region MemoryUsed -- 内存使用量
private ulong memoryUsed;
/// <summary>
/// 内存使用量
/// </summary>
public ulong MemoryUsed
{
get { return memoryUsed; }
set { memoryUsed = value; this.RaisePropertyChanged(nameof(MemoryUsed)); }
}
#endregion
#region MemoryTotal -- 内存总量
private ulong memoryTotal;
/// <summary>
/// 内存总量
/// </summary>
public ulong MemoryTotal
{
get { return memoryTotal; }
set { memoryTotal = value; this.RaisePropertyChanged(nameof(MemoryTotal)); }
}
#endregion
#region GpuModels -- GPU模型集合
private ObservableCollection<SystemMonitorGpuModel> gpuModels = new ObservableCollection<SystemMonitorGpuModel>();
/// <summary>
/// GPU模型集合
/// </summary>
public ObservableCollection<SystemMonitorGpuModel> GpuModels
{
get { return gpuModels; }
set { gpuModels = value; this.RaisePropertyChanged(nameof(GpuModels)); }
}
#endregion
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("VIZ.Framework.Domain")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.Domain")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("28661e82-c86a-4611-a028-c34f6ac85c97")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
<?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>{28661E82-C86A-4611-A028-C34F6AC85C97}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VIZ.Framework.Domain</RootNamespace>
<AssemblyName>VIZ.Framework.Domain</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ApplicationDomain.cs" />
<Compile Include="Message\UDP\UdpConsoleMessage.cs" />
<Compile Include="Model\Monitor\System\SystemMonitorGpuModel.cs" />
<Compile Include="Model\Monitor\System\SystemMonitorModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Initialize\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("VIZ.Framework.Module")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.Module")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace VIZ.Framework.Module.Properties {
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[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>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </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("VIZ.Framework.Module.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
<?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>
\ No newline at end of file
//------------------------------------------------------------------------------
// <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 VIZ.Framework.Module.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.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;
}
}
}
}
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using log4net;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动
/// </summary>
public static class AppSetup
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup));
/// <summary>
/// 应用程序启动
/// </summary>
private static List<IAppSetup> appSetups = new List<IAppSetup>();
/// <summary>
/// 应用程序加载
/// </summary>
private static List<IAppSetup> appLoads = new List<IAppSetup>();
/// <summary>
/// 是否已经启动
/// </summary>
public static bool IsSetup { get; private set; }
static AppSetup()
{
// 初始化应用程序启动
InitSetup();
// 初始化应用程序加载
InitLoad();
}
/// <summary>
/// 应用程序启动
/// </summary>
private static void InitSetup()
{
// Step 1. 单例启动
appSetups.Add(new AppSetup_Single());
// Step 2. 捕获未处理异常
appSetups.Add(new AppSetup_CatchUnhandledException());
// Step 3. 初始化日志
appSetups.Add(new AppSetup_LogInit());
// Step 4. 初始化延时
appSetups.Add(new AppSetup_DelayInit());
// Step 5. 初始化循环
appSetups.Add(new AppSetup_Loop());
}
/// <summary>
/// 应用程序加载
/// </summary>
private static void InitLoad()
{
}
/// <summary>
/// 执行
/// </summary>
/// <returns>应用程序启动上下文</returns>
public static AppSetupContext Setup()
{
Stopwatch stopwatch = Stopwatch.StartNew();
AppSetupContext context = new AppSetupContext();
if (IsSetup)
{
context.IsSuccess = false;
context.Remarks.Add("app is already setup.");
return context;
}
foreach (IAppSetup setup in appSetups)
{
try
{
if (!setup.IsEnabled)
continue;
stopwatch.Start();
if (setup.Setup(context))
{
stopwatch.Stop();
Debug.WriteLine($"Setup || {setup.Detail} ==> {stopwatch.ElapsedMilliseconds}");
continue;
}
context.IsSuccess = false;
context.ProviderDetail = setup.Detail;
return context;
}
catch (Exception ex)
{
log.Error(ex);
context.IsSuccess = false;
context.ProviderDetail = setup.Detail;
context.Exception = ex;
return context;
}
}
context.IsSuccess = true;
IsSetup = true;
stopwatch.Stop();
return context;
}
/// <summary>
/// 关闭
/// </summary>
public static void ShutDown()
{
if (!IsSetup)
return;
Stopwatch stopwatch = Stopwatch.StartNew();
AppSetupContext context = new AppSetupContext();
foreach (IAppSetup setup in appSetups)
{
try
{
if (!setup.IsEnabled)
continue;
stopwatch.Start();
setup.Shutdown(context);
stopwatch.Stop();
Debug.WriteLine($"ShutDown || {setup.Detail} ==> {stopwatch.ElapsedMilliseconds}");
}
catch (Exception ex)
{
log.Error(ex);
}
}
stopwatch.Stop();
IsSetup = false;
}
/// <summary>
/// 加载
/// </summary>
/// <returns>启动上下文</returns>
public static AppSetupContext Load()
{
Stopwatch stopwatch = Stopwatch.StartNew();
AppSetupContext context = new AppSetupContext();
foreach (IAppSetup setup in appLoads)
{
try
{
if (!setup.IsEnabled)
continue;
stopwatch.Start();
if (setup.Setup(context))
{
stopwatch.Stop();
Debug.WriteLine($"Load || {setup.Detail} ==> {stopwatch.ElapsedMilliseconds}");
continue;
}
context.IsSuccess = false;
context.ProviderDetail = setup.Detail;
return context;
}
catch (Exception ex)
{
log.Error(ex);
context.IsSuccess = false;
context.ProviderDetail = setup.Detail;
context.Exception = ex;
return context;
}
}
context.IsSuccess = true;
stopwatch.Stop();
return context;
}
/// <summary>
/// 卸载
/// </summary>
public static void UnLoad()
{
Stopwatch stopwatch = Stopwatch.StartNew();
AppSetupContext context = new AppSetupContext();
foreach (IAppSetup setup in appLoads)
{
try
{
if (!setup.IsEnabled)
continue;
stopwatch.Start();
setup.Shutdown(context);
stopwatch.Stop();
Debug.WriteLine($"UnLoad || {setup.Detail} ==> {stopwatch.ElapsedMilliseconds}");
}
catch (Exception ex)
{
log.Error(ex);
}
}
stopwatch.Stop();
}
/// <summary>
/// 添加启动项
/// </summary>
/// <param name="setup">启动项</param>
public static void AppendSetup(IAppSetup setup)
{
appSetups.Add(setup);
}
/// <summary>
/// 添加加载项
/// </summary>
/// <param name="setup">加载项</param>
public static void AppendLoad(IAppSetup setup)
{
appLoads.Add(setup);
}
/// <summary>
/// 获取所有的启动项
/// </summary>
/// <returns>启动项</returns>
public static List<IAppSetup> GetAppSetups()
{
return appSetups;
}
/// <summary>
/// 获取所有的加载项
/// </summary>
/// <returns>加载项</returns>
public static List<IAppSetup> GetAppLoads()
{
return appLoads;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动基类
/// </summary>
public abstract class AppSetupBase : IAppSetup
{
/// <summary>
/// 描述
/// </summary>
public abstract string Detail { get; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public abstract bool Setup(AppSetupContext context);
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public abstract void Shutdown(AppSetupContext context);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动上下文
/// </summary>
public class AppSetupContext
{
/// <summary>
/// 执行器描述信息
/// </summary>
public string ProviderDetail { get; set; }
/// <summary>
/// 备注
/// </summary>
public List<string> Remarks { get; set; }
/// <summary>
/// 异常信息
/// </summary>
public Exception Exception { get; set; }
/// <summary>
/// 是否执行成功
/// </summary>
public bool IsSuccess { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动
/// </summary>
public interface IAppSetup
{
/// <summary>
/// 描述
/// </summary>
string Detail { get; }
/// <summary>
/// 是否启用
/// </summary>
bool IsEnabled { get; set; }
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
bool Setup(AppSetupContext context);
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
void Shutdown(AppSetupContext context);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using System.Threading;
using VIZ.Framework.Domain;
using VIZ.Framework.Core;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动 -- 监控
/// </summary>
public class AppSetup_Monitor : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_Monitor));
/// <summary>
/// 描述
/// </summary>
public override string Detail { get; } = "应用程序启动 -- 监控";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public override bool Setup(AppSetupContext context)
{
Task.Run(() =>
{
try
{
ApplicationDomain.MonitorManager.AppendTask(new SystemMonitorTask());
ApplicationDomain.MonitorManager.Start();
}
catch (Exception ex)
{
log.Error(ex);
}
});
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public override void Shutdown(AppSetupContext context)
{
ApplicationDomain.MonitorManager.Stop();
}
}
}
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动 -- 捕获未处理异常
/// </summary>
public class AppSetup_CatchUnhandledException : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_CatchUnhandledException));
/// <summary>
/// 描述
/// </summary>
public override string Detail { get; } = "应用程序启动 -- 捕获未处理异常";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public override bool Setup(AppSetupContext context)
{
Application.Current.DispatcherUnhandledException -= App_DispatcherUnhandledException;
Application.Current.DispatcherUnhandledException += App_DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public override void Shutdown(AppSetupContext context)
{
}
/// <summary>
/// 应用程序未处理异常
/// </summary>
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Debug.WriteLine(e.ExceptionObject);
log.Error(e.ExceptionObject);
}
/// <summary>
/// WPF应用程序未处理异常
/// </summary>
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
Debug.WriteLine(e.Exception.Message);
log.Error(e.Exception);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using VIZ.Framework.Connection;
using VIZ.Framework.Storage;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动 -- 初始化延时
/// </summary>
public class AppSetup_DelayInit : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_DelayInit));
/// <summary>
/// 描述
/// </summary>
public override string Detail { get; } = "应用程序启动 -- 初始化延时";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public override bool Setup(AppSetupContext context)
{
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public override void Shutdown(AppSetupContext context)
{
ApplicationDomain.DelayManager?.Dispose();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using VIZ.Framework.Connection;
using VIZ.Framework.Storage;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动 -- 日志初始化
/// </summary>
public class AppSetup_LogInit : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_LogInit));
/// <summary>
/// 描述
/// </summary>
public override string Detail { get; } = "应用程序启动 -- 日志初始化";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public override bool Setup(AppSetupContext context)
{
string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "log.config");
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(path));
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public override void Shutdown(AppSetupContext context)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using VIZ.Framework.Connection;
using VIZ.Framework.Storage;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动 -- 循环
/// </summary>
public class AppSetup_Loop : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_Loop));
/// <summary>
/// 描述
/// </summary>
public override string Detail { get; } = "应用程序启动 -- 循环";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public override bool Setup(AppSetupContext context)
{
ApplicationDomain.LoopManager.Start();
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public override void Shutdown(AppSetupContext context)
{
ApplicationDomain.LoopManager?.Dispose();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using VIZ.Framework.Connection;
using VIZ.Framework.Storage;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动 -- 3D鼠标
/// </summary>
public class AppSetup_Navigation3D : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_Navigation3D));
/// <summary>
/// 描述
/// </summary>
public override string Detail { get; } = "应用程序启动 -- 3D鼠标";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public override bool Setup(AppSetupContext context)
{
string profileName = ApplicationDomain.IniStorage.GetValue<Navigation3DConfig, string>(p => p.NAVIGATION3D_PROFILE_NAME);
double maxX = ApplicationDomain.IniStorage.GetValue<Navigation3DConfig, double>(p => p.NAVIGATION3D_MAX_VALUE);
Navigation3DManager.Init(profileName, maxX);
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public override void Shutdown(AppSetupContext context)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using System.Threading;
using VIZ.Framework.Domain;
namespace VIZ.Framework.Module
{
/// <summary>
/// 应用程序启动 -- 单例启动
/// </summary>
public class AppSetup_Single : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_Single));
/// <summary>
///
/// </summary>
private EventWaitHandle ProgramStarted;
/// <summary>
/// 描述
/// </summary>
public override string Detail { get; } = "应用程序启动 -- 单例启动";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public override bool Setup(AppSetupContext context)
{
string applicationName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
bool createNew;
this.ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, applicationName, out createNew);
if (!createNew)
{
ProgramStarted.Set();
return false;
}
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public override void Shutdown(AppSetupContext context)
{
}
}
}
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VIZ.Framework.Module">
</ResourceDictionary>
<?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>{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}</ProjectGuid>
<OutputType>library</OutputType>
<RootNamespace>VIZ.Framework.Module</RootNamespace>
<AssemblyName>VIZ.Framework.Module</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=2.0.14.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.14\lib\net45\log4net.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<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>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</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>
<Compile Include="Setup\AppSetup.cs" />
<Compile Include="Setup\AppSetupBase.cs" />
<Compile Include="Setup\AppSetupContext.cs" />
<Compile Include="Setup\IAppSetup.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_CatchUnhandledException.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_Navigation3D.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_Loop.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_DelayInit.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_LogInit.cs" />
<Compile Include="Setup\Provider\Load\AppSetup_Monitor.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_Single.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.Framework.Common.Resource\VIZ.Framework.Common.Resource.csproj">
<Project>{76ef480a-e486-41b7-b7a5-2a849fc8d5bf}</Project>
<Name>VIZ.Framework.Common.Resource</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Connection\VIZ.Framework.Connection.csproj">
<Project>{e07528dd-9dee-47c2-b79d-235ecfa6b003}</Project>
<Name>VIZ.Framework.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.14" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
</packages>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Storage
{
/// <summary>
/// 3D鼠标配置
/// </summary>
public class Navigation3DConfig : IniConfigBase
{
/// <summary>
/// 3D鼠标X轴偏移最大值
/// </summary>
[Ini(Section = "Navigation3D", DefaultValue = "3", Type = typeof(double))]
public string NAVIGATION3D_MAX_VALUE { get; set; }
/// <summary>
/// 3D鼠标配置名称
/// </summary>
[Ini(Section = "Navigation3D", DefaultValue = "VIZ.Framework", Type = typeof(string))]
public string NAVIGATION3D_PROFILE_NAME { get; set; }
}
}
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Storage
{
/// <summary>
/// 视频 配置
/// </summary>
public class VideoConfig : IniConfigBase
{
/// <summary>
/// 是否显示FPS (True | Flase)
/// </summary>
[Ini(Section = "Video", DefaultValue = "Flase", Type = typeof(bool))]
public string VIDEO_IS_SHOW_FPS { get; set; }
/// <summary>
/// 视频渲染等待(单位:毫秒)
/// </summary>
[Ini(Section = "Video", DefaultValue = "5", Type = typeof(int))]
public string VIDEO_RENDER_WAIT { get; set; }
/// <summary>
/// 视频背景颜色
/// </summary>
[Ini(Section = "Video", DefaultValue = "#FF000000", Type = typeof(RawColor4))]
public string VIDEO_BACKGROUND_COLOR { get; set; }
/// <summary>
/// 跟踪框边框宽度(单位:像素)
/// </summary>
[Ini(Section = "Video", DefaultValue = "4", Type = typeof(int))]
public string VIDEO_TRACKING_BOX_BORDER_WIDTH { get; set; }
/// <summary>
/// 跟踪框边框颜色(格式:#AARRGGBB)
/// </summary>
[Ini(Section = "Video", DefaultValue = "#FFFF0000", Type = typeof(RawColor4))]
public string VIDEO_TRACKING_BOX_BORDER_COLOR { get; set; }
/// <summary>
/// 框选框边框宽度(单位:像素)
/// </summary>
[Ini(Section = "Video", DefaultValue = "4", Type = typeof(int))]
public string VIDEO_SELECTION_BOX_BORDER_WIDTH { get; set; }
/// <summary>
/// 框选框边框颜色(格式:#AARRGGBB)
/// </summary>
[Ini(Section = "Video", DefaultValue = "#FFFF6D87", Type = typeof(RawColor4))]
public string VIDEO_SELECTION_BOX_BORDER_COLOR { get; set; }
/// <summary>
/// 剪切框宽度(单位:像素)
/// </summary>
[Ini(Section = "Video", DefaultValue = "810", Type = typeof(int))]
public string VIDEO_CLIP_BOX_WIDTH { get; set; }
/// <summary>
/// 剪切框边框宽度(单位:像素)
/// </summary>
[Ini(Section = "Video", DefaultValue = "4", Type = typeof(int))]
public string VIDEO_CLIP_BOX_BORDER_WIDTH { get; set; }
/// <summary>
/// 剪切框边框颜色
/// </summary>
[Ini(Section = "Video", DefaultValue = "#FFFF0000", Type = typeof(RawColor4))]
public string VIDEO_CLIP_BOX_BORDER_COLOR { get; set; }
/// <summary>
/// 剪切掩码颜色
/// </summary>
[Ini(Section = "Video", DefaultValue = "#44000000", Type = typeof(RawColor4))]
public string VIDEO_CLIP_BOX_MASK_COLOR { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Storage
{
/// <summary>
/// Ini配置
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class IniAttribute : Attribute
{
/// <summary>
/// 区域
/// </summary>
public string Section { get; set; }
/// <summary>
/// 默认值
/// </summary>
public string DefaultValue { get; set; }
/// <summary>
/// 值类型
/// </summary>
public Type Type { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.Framework.Storage
{
/// <summary>
/// INI配置基类
/// </summary>
public abstract class IniConfigBase
{
}
}
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
namespace VIZ.Framework.Storage
{
/// <summary>
/// Ini仓储
/// </summary>
public class IniStorage
{
/// <summary>
/// 每次读取最大值
/// </summary>
public const int MAX_READ_SIZE = 255;
/// <summary>
/// 声明INI文件的写操作函数
/// </summary>
/// <param name="section">配置节</param>
/// <param name="key">键</param>
/// <param name="val">值</param>
/// <param name="filePath">Ini文件路径</param>
/// <returns></returns>
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
/// <summary>
/// 声明INI文件的读操作函数
/// </summary>
/// <param name="section">配置节</param>
/// <param name="key">键</param>
/// <param name="def">默认值</param>
/// <param name="retVal">返回值</param>
/// <param name="size">目标缓存器大小</param>
/// <param name="filePath">Ini文件路径</param>
/// <returns></returns>
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string def, System.Text.StringBuilder retVal, int size, string filePath);
private string sPath = null;
/// <summary>
/// Ini文件仓储
/// </summary>
/// <param name="path">Ini文件路径</param>
public IniStorage(string path)
{
this.sPath = path;
}
/// <summary>
/// 设置值
/// </summary>
/// <param name="section">配置节</param>
/// <param name="key">键</param>
/// <param name="value">值</param>
public void SetValue(string section, string key, string value)
{
// section=配置节,key=键名,value=键值,path=路径
WritePrivateProfileString(section, key, value, sPath);
}
/// <summary>
/// 获取值
/// </summary>
/// <param name="section">配置节</param>
/// <param name="key">键</param>
/// <returns>值</returns>
public string GetValue(string section, string key)
{
// 每次从ini中读取多少字节
StringBuilder temp = new StringBuilder(MAX_READ_SIZE);
// section=配置节,key=键名,temp=上面,path=路径
GetPrivateProfileString(section, key, string.Empty, temp, MAX_READ_SIZE, sPath);
return temp.ToString();
}
/// <summary>
/// 获取值
/// </summary>
/// <typeparam name="TConfig">配置对象类型</typeparam>
/// <typeparam name="TValue">配置值类型</typeparam>
/// <typeparam name="TProperty">属性类型</typeparam>
/// <param name="property">属性选择器</param>
/// <returns>配置值</returns>
public TValue GetValue<TConfig, TValue>(Expression<Func<TConfig, string>> property) where TConfig : IniConfigBase
{
Type type = typeof(TConfig);
string str_property = property.ToString();
string propertyName = str_property.Substring(str_property.IndexOf('.') + 1);
PropertyInfo propertyInfo = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
throw new Exception($"{str_property} is not found.");
IniAttribute attribute = propertyInfo.GetCustomAttribute<IniAttribute>(true);
if (attribute == null)
throw new Exception($"{str_property} no IniAttribute.");
// 每次从ini中读取多少字节
StringBuilder temp = new StringBuilder(MAX_READ_SIZE);
// section=配置节,key=键名,temp=上面,path=路径
GetPrivateProfileString(attribute.Section, propertyName, attribute.DefaultValue, temp, MAX_READ_SIZE, sPath);
TValue result = this.ConvertValue<TValue>(temp?.ToString());
return result;
}
/// <summary>
/// 设置值
/// </summary>
/// <typeparam name="T">配置对象类型</typeparam>
/// <param name="property">属性选择器</param>
/// <param name="value">属性值</param>
public void SetValue<T>(Expression<Func<T, string>> property, object value) where T : IniConfigBase
{
Type type = typeof(T);
string str_property = property.ToString();
string propertyName = str_property.Substring(str_property.IndexOf('.') + 1);
PropertyInfo propertyInfo = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
throw new Exception($"{str_property} is not found.");
IniAttribute attribute = propertyInfo.GetCustomAttribute<IniAttribute>(true);
if (attribute == null)
throw new Exception($"{str_property} no IniAttribute.");
// section=配置节,key=键名,value=键值,path=路径
WritePrivateProfileString(attribute.Section, propertyName, (value == null ? string.Empty : value.ToString()), sPath);
}
/// <summary>
/// 转化类型
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
private TValue ConvertValue<TValue>(string value)
{
if (string.IsNullOrEmpty(value))
return default;
Type type = typeof(TValue);
// String
if (type == typeof(string))
return (TValue)(object)value;
// Int32
if (type == typeof(Int32))
return (TValue)(object)Convert.ToInt32(value);
// Int64
if (type == typeof(Int64))
return (TValue)(object)Convert.ToInt64(value);
// Float
if (type == typeof(float))
return (TValue)(object)(float)Convert.ToDouble(value);
// Double
if (type == typeof(double))
return (TValue)(object)Convert.ToDouble(value);
// Bool
if (type == typeof(bool))
return (TValue)(object)Convert.ToBoolean(value);
// RawColor4
if (type == typeof(RawColor4))
return (TValue)(object)SharpDxColorHelper.FromString(value);
return default;
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("VIZ.Framework.Storage")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.Storage")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("06b80c09-343d-4bb2-aeb1-61cfbfbf5cad")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
<?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>{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VIZ.Framework.Storage</RootNamespace>
<AssemblyName>VIZ.Framework.Storage</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=2.0.14.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.14\lib\net45\log4net.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Mathematics, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Ini\Config\Navigation3DConfig.cs" />
<Compile Include="Ini\Config\VideoConfig.cs" />
<Compile Include="Ini\IniAttribute.cs" />
<Compile Include="Ini\IniConfigBase.cs" />
<Compile Include="Ini\IniStorage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.14" targetFramework="net48" />
<package id="SharpDX" version="4.2.0" targetFramework="net48" />
<package id="SharpDX.Mathematics" version="4.2.0" targetFramework="net48" />
</packages>
\ No newline at end of file
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Diagnostics;
using VIZ.Framework.Core;
namespace VIZ.Framework.UnitTest
{
/// <summary>
/// 监控测试
/// </summary>
[TestClass]
public class MonitorTask
{
private MonitorManager manager = new MonitorManager();
/// <summary>
/// 初始化
/// </summary>
[TestInitialize]
public void Initialize()
{
this.manager.AppendTask(new SystemMonitorTask());
this.manager.Start();
}
/// <summary>
/// 清理
/// </summary>
[TestCleanup]
public void Cleanup()
{
this.manager.Stop();
}
/// <summary>
/// 系统监视测试
/// </summary>
[TestMethod]
public void SystemTest()
{
SystemMonitorInfo info = this.manager.GetInfo<SystemMonitorInfo>("System");
int i = 0;
while (i++ < 30)
{
System.Threading.Thread.Sleep(1000);
Debug.WriteLine("--------------------------------------");
Debug.WriteLine($"CPU: {info.CpuUsedPercentage}");
Debug.WriteLine($"内存: {info.MemoryUsedPercentage}");
Debug.WriteLine("--------------------------------------");
}
}
/// <summary>
/// 字节大小转化测试
/// </summary>
[TestMethod]
public void BitSizeConverterTest()
{
ByteSizeConverter converter = new ByteSizeConverter();
converter.InType = ByteSizeType.B;
converter.OutType = ByteSizeType.MB;
object r = converter.Convert(1024 * 1024, null, null, null);
object rb = converter.ConvertBack(r, null, null, null);
}
}
}
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using VIZ.H2V.Connection;
namespace VIZ.Framework.UnitTest
{
/// <summary>
/// 监控测试
/// </summary>
[TestClass]
public class NetTest
{
/// <summary>
/// 获取Mac地址测试
/// </summary>
[TestMethod]
public void GetMacTest()
{
string str = NetHelper.GetMacAddress();
Assert.IsTrue(!string.IsNullOrWhiteSpace(str));
}
/// <summary>
/// 获取可用的UDP端口
/// </summary>
[TestMethod]
public void GetUdpPortTest()
{
int port = NetHelper.GetAvailableUdpPort(8000, 9000, null);
try
{
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);
UdpClient client = new UdpClient(ipep);
}
catch
{
}
Assert.IsTrue(port >= 8000 && port <= 20000);
}
[TestMethod]
public void JosnTest()
{
string str = "{'signal': 'detect', 'bboxes': [[914.5606, 144.6889, 1877.504, 380.21176]], 'id': 'E0:4F:43:E6:48:C2__CAM_1'}";
AlgorithmPackageBase @base = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmPackageBase>(str);
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("VIZ.Framework.UnitTest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.UnitTest")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("f9862446-b144-42f1-87a4-faf3707268a6")]
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.props')" />
<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>{F9862446-B144-42F1-87A4-FAF3707268A6}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VIZ.Framework.UnitTest</RootNamespace>
<AssemblyName>VIZ.Framework.UnitTest</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.7\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.7\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="MonitorTask.cs" />
<Compile Include="NetTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\VIZ.H2V\VIZ.H2V.Connection\VIZ.H2V.Connection.csproj">
<Project>{94C95C0F-070F-4827-83FC-8DDA63BAB177}</Project>
<Name>VIZ.H2V.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Common.Resource\VIZ.Framework.Common.Resource.csproj">
<Project>{76ef480a-e486-41b7-b7a5-2a849fc8d5bf}</Project>
<Name>VIZ.Framework.Common.Resource</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Connection\VIZ.Framework.Connection.csproj">
<Project>{e07528dd-9dee-47c2-b79d-235ecfa6b003}</Project>
<Name>VIZ.Framework.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.targets'))" />
</Target>
<Import Project="..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.targets')" />
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MSTest.TestAdapter" version="2.2.7" targetFramework="net48" />
<package id="MSTest.TestFramework" version="2.2.7" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
</packages>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
<Application x:Class="VIZ.Framework.WpfTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VIZ.Framework.WpfTest"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using VIZ.Framework.Domain;
using VIZ.Framework.Module;
namespace VIZ.Framework.WpfTest
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
AppSetup.Setup();
}
protected override void OnExit(ExitEventArgs e)
{
AppSetup.ShutDown();
base.OnExit(e);
}
}
}
<Window x:Class="VIZ.Framework.WpfTest.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:VIZ.Framework.WpfTest"
xmlns:fcommon="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
mc:Ignorable="d" WindowStartupLocation="CenterScreen" WindowState="Maximized" WindowStyle="None"
Title="MainWindow" Height="800" Width="1200">
<Grid>
<local:NumberBoxTest></local:NumberBoxTest>
</Grid>
</Window>
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 VIZ.Framework.WpfTest
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
<UserControl x:Class="VIZ.Framework.WpfTest.NavigationTest"
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"
xmlns:fcommon="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
xmlns:local="clr-namespace:VIZ.Framework.WpfTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<fcommon:NavigationControl x:Name="navigation">
<fcommon:NavigationItemControl ViewType="{x:Type local:UserControl1}" IsSelected="True"></fcommon:NavigationItemControl>
<fcommon:NavigationItemControl ViewType="{x:Type local:UserControl2}"></fcommon:NavigationItemControl>
</fcommon:NavigationControl>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button Width="120" Height="40" Content="UC1" Margin="20,0,20,0" Click="Button_Click"></Button>
<Button Width="120" Height="40" Content="UC2" Margin="20,0,20,0" Click="Button_Click_1"></Button>
</StackPanel>
</Grid>
</UserControl>
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;
using VIZ.Framework.Common;
namespace VIZ.Framework.WpfTest
{
/// <summary>
/// NavigationTest.xaml 的交互逻辑
/// </summary>
public partial class NavigationTest : UserControl
{
public NavigationTest()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.navigation.SelectedIndex = 0;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.navigation.SelectedIndex = 1;
}
}
}
<UserControl x:Class="VIZ.Framework.WpfTest.NavigationTest2"
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"
xmlns:fcommon="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
xmlns:local="clr-namespace:VIZ.Framework.WpfTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/VIZ.Framework.Common;component/Widgets/NavigationControl/NavigationControl.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<fcommon:NavigationControl x:Name="navigation" ItemsSource="{Binding Path=Items}" SelectedValue="{Binding Path=SelectedItem,Mode=TwoWay}">
</fcommon:NavigationControl>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button Width="120" Height="40" Content="UC1" Margin="20,0,20,0" Click="Button_Click"></Button>
<Button Width="120" Height="40" Content="UC2" Margin="20,0,20,0" Click="Button_Click_1"></Button>
</StackPanel>
</Grid>
</UserControl>
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;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
namespace VIZ.Framework.WpfTest
{
public class NavigationTestModel : ModelBase
{
private List<NavigationConfig> items;
public List<NavigationConfig> Items
{
get { return items; }
set { items = value; this.RaisePropertyChanged(nameof(items)); }
}
private NavigationConfig selectedItem;
public NavigationConfig SelectedItem
{
get { return selectedItem; }
set { selectedItem = value; this.RaisePropertyChanged(nameof(SelectedItem)); }
}
}
/// <summary>
/// NavigationTest2.xaml 的交互逻辑
/// </summary>
public partial class NavigationTest2 : UserControl
{
public NavigationTest2()
{
InitializeComponent();
model = new NavigationTestModel();
model.Items = new List<NavigationConfig>();
model.Items.Add(new NavigationConfig { ViewType = typeof(UserControl1) });
model.Items.Add(new NavigationConfig { ViewType = typeof(UserControl2) });
this.DataContext = model;
}
private NavigationTestModel model;
private void Button_Click(object sender, RoutedEventArgs e)
{
model.SelectedItem = model.Items[0];
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
model.SelectedItem = model.Items[1];
}
}
}
<UserControl x:Class="VIZ.Framework.WpfTest.UserControl1"
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"
xmlns:local="clr-namespace:VIZ.Framework.WpfTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Text="UserControl1" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="48" Foreground="Red"></TextBlock>
</Grid>
</UserControl>
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 VIZ.Framework.WpfTest
{
/// <summary>
/// UserControl1.xaml 的交互逻辑
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
}
}
<UserControl x:Class="VIZ.Framework.WpfTest.UserControl2"
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"
xmlns:local="clr-namespace:VIZ.Framework.WpfTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Text="UserControl2" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="48" Foreground="Red"></TextBlock>
</Grid>
</UserControl>
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 VIZ.Framework.WpfTest
{
/// <summary>
/// UserControl2.xaml 的交互逻辑
/// </summary>
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
}
}
}
<UserControl x:Class="VIZ.Framework.WpfTest.NumberBoxTest"
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"
xmlns:local="clr-namespace:VIZ.Framework.WpfTest"
xmlns:fcommon="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
mc:Ignorable="d" Background="Pink"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/VIZ.Framework.Common.Resource;component/Style/NumberBox/NumberBox.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<fcommon:NumberBox Height="40" Width="240" Interval="0.1" Value="{Binding Path=Value,Mode=TwoWay}"></fcommon:NumberBox>
<Button Width="120" Height="30" Margin="0,200,0,0" Click="Button_Click"></Button>
</Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 VIZ.Framework.Core;
namespace VIZ.Framework.WpfTest
{
public class Test : ModelBase
{
private double _value;
public double Value
{
get { return _value; }
set
{
_value = value;
this.RaisePropertyChanged(nameof(Value));
Debug.WriteLine(_value);
}
}
}
/// <summary>
/// NumberBoxTest.xaml 的交互逻辑
/// </summary>
public partial class NumberBoxTest : UserControl
{
public NumberBoxTest()
{
InitializeComponent();
this.Test = new Test();
this.DataContext = this.Test;
}
private Test Test;
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Test.Value = 102;
}
}
}
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("VIZ.Framework.WpfTest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VIZ.Framework.WpfTest")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace VIZ.Framework.WpfTest.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[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>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </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("VIZ.Framework.WpfTest.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
<?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>
\ No newline at end of file
//------------------------------------------------------------------------------
// <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 VIZ.Framework.WpfTest.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.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;
}
}
}
}
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
\ No newline at end of file
<?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>{B62C822E-701F-480F-BBB1-0E02217D622C}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>VIZ.Framework.WpfTest</RootNamespace>
<AssemblyName>VIZ.Framework.WpfTest</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 Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\OpenCvSharp4.4.6.0.20220608\lib\net48\OpenCvSharp.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Security" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\VIZ.H2V\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<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>
<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="NavigationTest\NavigationTest2.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="NavigationTest\NavigationTest.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="NavigationTest\UserControl1.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="NavigationTest\UserControl2.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="NumberBoxTest\NumberBoxTest.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="VideoRender\OpenCVVideoTest.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="NavigationTest\NavigationTest2.xaml.cs">
<DependentUpon>NavigationTest2.xaml</DependentUpon>
</Compile>
<Compile Include="NavigationTest\NavigationTest.xaml.cs">
<DependentUpon>NavigationTest.xaml</DependentUpon>
</Compile>
<Compile Include="NavigationTest\UserControl1.xaml.cs">
<DependentUpon>UserControl1.xaml</DependentUpon>
</Compile>
<Compile Include="NavigationTest\UserControl2.xaml.cs">
<DependentUpon>UserControl2.xaml</DependentUpon>
</Compile>
<Compile Include="NumberBoxTest\NumberBoxTest.xaml.cs">
<DependentUpon>NumberBoxTest.xaml</DependentUpon>
</Compile>
<Compile Include="VideoRender\OpenCVVideoTest.xaml.cs">
<DependentUpon>OpenCVVideoTest.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="config\config.ini">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="config\log.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<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>
<ProjectReference Include="..\VIZ.Framework.Common.Resource\VIZ.Framework.Common.Resource.csproj">
<Project>{76ef480a-e486-41b7-b7a5-2a849fc8d5bf}</Project>
<Name>VIZ.Framework.Common.Resource</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Connection\VIZ.Framework.Connection.csproj">
<Project>{e07528dd-9dee-47c2-b79d-235ecfa6b003}</Project>
<Name>VIZ.Framework.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Module\VIZ.Framework.Module.csproj">
<Project>{47cf6fb0-e37d-4ef1-afc7-03db2bca8892}</Project>
<Name>VIZ.Framework.Module</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
<UserControl x:Class="VIZ.Framework.WpfTest.OpenCVVideoTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:common="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
mc:Ignorable="d" Loaded="UserControl_Loaded"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="Yellow">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<common:VideoControl x:Name="video" IsShowFPS="True" Height="800" Margin="40,0,40,0"></common:VideoControl>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<Button Margin="10,0,10,0" Width="120" Height="40" Content="图片测试" Click="Button_Click"></Button>
<Button Margin="10,0,10,0" Width="120" Height="40" Content="清理裁剪框" Click="Button_Click2"></Button>
</StackPanel>
</Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 VIZ.Framework.Common;
using VIZ.Framework.Core;
namespace VIZ.Framework.WpfTest
{
/// <summary>
/// OpenCVVideoTest.xaml 的交互逻辑
/// </summary>
public partial class OpenCVVideoTest : UserControl
{
public OpenCVVideoTest()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
// 附加插件
TrackingBoxPlugin trackingBoxPlugin = new TrackingBoxPlugin(this.video);
trackingBoxPlugin.TrackingBoxClick += TrackingBoxPlugin_TrackingBoxClick;
SelectionBoxPlugin selectionBoxPlugin = new SelectionBoxPlugin(this.video);
selectionBoxPlugin.Selected += SelectionBoxPlugin_Selected;
ClipBoxPlugin clipBoxPlugin = new ClipBoxPlugin(this.video);
this.video.AttachPlugin(trackingBoxPlugin);
this.video.AttachPlugin(selectionBoxPlugin);
this.video.AttachPlugin(clipBoxPlugin);
// 接入OpenCV插件
OpenCVStreamOption option = new OpenCVStreamOption();
OpenCVStream stream = new OpenCVStream(option);
stream.ExecuteVideoFrame += Stream_ExecuteVideoFrame;
stream.ChangeUri(@"E:\视频\1.mp4");
stream.Play();
// 更新矩形框信息
List<TrackingBoxInfo> list = new List<TrackingBoxInfo>();
list.Add(new TrackingBoxInfo
{
DrawingBorderColor = SharpDxColorHelper.FromString("#FFFF0000"),
ID = "1",
DrawingBorderWidth = 4,
SrcRect = new SharpDX.Mathematics.Interop.RawRectangleF(0, 0, 200, 120)
});
list.Add(new TrackingBoxInfo
{
DrawingBorderColor = SharpDxColorHelper.FromString("#FFFF0000"),
ID = "1",
DrawingBorderWidth = 4,
SrcRect = new SharpDX.Mathematics.Interop.RawRectangleF(400, 300, 600, 420)
});
this.video.UpdateTrackingBox(list);
// 裁剪
ClipBoxInfo clipBoxInfo = new ClipBoxInfo();
clipBoxInfo.DrawingBorderWidth = 8;
clipBoxInfo.DrawingBorderColor = SharpDxColorHelper.FromString("#AA0000FF");
clipBoxInfo.MaskColor = SharpDxColorHelper.FromString("#66000000");
clipBoxInfo.SrcRect = new SharpDX.Mathematics.Interop.RawRectangleF(200, 0, 800, 1080);
this.video.UpdateClipBox(clipBoxInfo);
}
private void Stream_ExecuteVideoFrame(object sender, VideoFrameEventArgs e)
{
this.video.UpdateVideoFrame(e.Frame);
}
private void SelectionBoxPlugin_Selected(object sender, SelectionBoxSelectedEventArgs e)
{
Rect rect = e.DrawingRect.ToRect();
Debug.WriteLine($"Slect: [{rect.X}, {rect.Y}, {rect.Width}, {rect.Height}]");
}
private void TrackingBoxPlugin_TrackingBoxClick(object sender, TrackingBoxClickEventArgs e)
{
TrackingBoxInfo info = e.HitTrackingBoxInfos.FirstOrDefault();
if (info == null)
return;
Rect rect = info.SrcRect.ToRect();
Debug.WriteLine($"Click: [{rect.X}, {rect.Y}, {rect.Width}, {rect.Height}]");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
OpenCvSharp.Mat mat = this.video.RenderVideoToMat(new List<string>
{
VideoControlPluginNames.TrackingBox,
VideoControlPluginNames.SelectionBox,
VideoControlPluginNames.ClipBox
});
mat.SaveImage(@"e:\1.jpg");
mat.Dispose();
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
this.video.ClearClipBox();
}
}
}
; ============================================================
; === Video ===
; ============================================================
[Video]
;视频是否显示FPS
VIDEO_IS_SHOW_FPS=false
;视频渲染等待(单位:毫秒)
VIDEO_RENDER_WAIT=5
;视频背景颜色
VIDEO_BACKGROUND_COLOR=#FFFF0000
;视频框宽度(单位:像素)
VIDEO_RECTANGLE_STROKE_WIDTH=4
;视频框颜色(格式:#AARRGGBB)
VIDEO_RECTANGLE_STROKE_COLOR=#FFFF0000
;视频框选宽度(单位:像素)
VIDEO_FRAME_SELECTION_STROKE_WIDTH=4
;视频框选颜色(格式:#AARRGGBB)
VIDEO_FRAME_SELECTION_STROKE_COLOR=#FFFF6D87
;视频剪切宽度
VIDEO_CLIP_BOX_WIDTH=810
;视频剪切框移动速度
VIDEO_CLIP_BOX_MOVE_SPEED=10
;视频剪切框宽度
VIDEO_CLIP_BOX_STROKE_WIDTH=4
;视频剪切框颜色
VIDEO_CLIP_BOX_STROKE_COLOR=#FFFF0000
;视频剪切掩码颜色
VIDEO_CLIP_BOX_MASK_COLOR=#88000000
; ============================================================
; === NDI ===
; ============================================================
[NDI]
;NDI CAM1 流名称
NDI_CAM_1_STREAM_NAME=LAPTOP-6ESNHBU6 (VLC)
;NDI CAM1 延时
NDI_CAM_1_VIDEO_DELAY = 0
;NDI CAM2 流名称
NDI_CAM_2_STREAM_NAME=
;NDI CAM2 延时
NDI_CAM_2_VIDEO_DELAY = 0
;NDI CAM3 流名称
NDI_CAM_3_STREAM_NAME=
;NDI CAM3 延时
NDI_CAM_3_VIDEO_DELAY = 0
;NDI CAM4 流名称
NDI_CAM_4_STREAM_NAME=
;NDI CAM4 延时
NDI_CAM_4_VIDEO_DELAY = 0
\ No newline at end of file
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="errorAppender" type="log4net.Appender.RollingFileAppender">
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="ERROR" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<file value="Logs\err.log" />
<encoding value="utf-8"/>
<preserveLogFileNameExtension value="true" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="infoAppender" type="log4net.Appender.RollingFileAppender">
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="INFO" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<file value="Logs\info.log" />
<encoding value="utf-8"/>
<preserveLogFileNameExtension value="true" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="debugAppender" type="log4net.Appender.RollingFileAppender">
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="DEBUG" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<file value="Logs\debug.log" />
<encoding value="utf-8"/>
<preserveLogFileNameExtension value="true" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="perfAppender" type="log4net.Appender.RollingFileAppender">
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="INFO" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<file value="Logs\perf.log" />
<encoding value="utf-8"/>
<preserveLogFileNameExtension value="true" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="errorAppender" />
<appender-ref ref="infoAppender" />
<appender-ref ref="debugAppender" />
</root>
<logger name="Performance" additivity="false">
<level value="ALL" />
<appender-ref ref="perfAppender" />
</logger>
</log4net>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="OpenCvSharp4" version="4.6.0.20220608" targetFramework="net48" />
<package id="SharpDX" version="4.2.0" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
</packages>
\ No newline at end of file

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32526.322
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "00-Doc", "00-Doc", "{12EDF2BB-8CC7-43DF-9723-8F77B6DB99C2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "05-Lib", "05-Lib", "{6BE77FA1-01ED-497D-A3B8-095DF03C8CBB}"
ProjectSection(SolutionItems) = preProject
05-Lib\NDILibDotNet2.dll = 05-Lib\NDILibDotNet2.dll
05-Lib\Processing.NDI.Lib.x64.dll = 05-Lib\Processing.NDI.Lib.x64.dll
05-Lib\Processing.NDI.Lib.x86.dll = 05-Lib\Processing.NDI.Lib.x86.dll
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "10-Core", "10-Core", "{2F6173AD-2376-4F42-B852-10E3DBD394EE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "30-Domain", "30-Domain", "{C04CA8B9-5D31-4E8A-9EFD-B1A5AFCEED98}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "40-Common", "40-Common", "{CF5B6846-34AF-4FF4-880D-58E34F1134F0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "50-Connection", "50-Connection", "{8AB3E51B-05BE-4C31-9975-8C12CBBF7177}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Core", "VIZ.Framework.Core\VIZ.Framework.Core.csproj", "{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Common", "VIZ.Framework.Common\VIZ.Framework.Common.csproj", "{92834C05-703E-4F05-9224-F36220939D8F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "20-Storage", "20-Storage", "{3D5227CE-FAE2-4A56-A303-687DD234FDE2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Storage", "VIZ.Framework.Storage\VIZ.Framework.Storage.csproj", "{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Domain", "VIZ.Framework.Domain\VIZ.Framework.Domain.csproj", "{28661E82-C86A-4611-A028-C34F6AC85C97}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "90-Test", "90-Test", "{C78D0841-72DB-4ED7-B200-2E7F20D9D6BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.WpfTest", "VIZ.Framework.WpfTest\VIZ.Framework.WpfTest.csproj", "{B62C822E-701F-480F-BBB1-0E02217D622C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Connection", "VIZ.Framework.Connection\VIZ.Framework.Connection.csproj", "{E07528DD-9DEE-47C2-B79D-235ECFA6B003}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Common.Resource", "VIZ.Framework.Common.Resource\VIZ.Framework.Common.Resource.csproj", "{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.UnitTest", "VIZ.Framework.UnitTest\VIZ.Framework.UnitTest.csproj", "{F9862446-B144-42F1-87A4-FAF3707268A6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60-Module", "60-Module", "{5EB5F581-9DF6-4166-AC5B-89E6851089E9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Module", "VIZ.Framework.Module\VIZ.Framework.Module.csproj", "{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|Any CPU.ActiveCfg = Debug|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|Any CPU.Build.0 = Debug|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|x64.ActiveCfg = Debug|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|x64.Build.0 = Debug|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|Any CPU.Build.0 = Release|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|x64.ActiveCfg = Release|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|x64.Build.0 = Release|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|Any CPU.ActiveCfg = Debug|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|Any CPU.Build.0 = Debug|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|x64.ActiveCfg = Debug|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|x64.Build.0 = Debug|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Release|Any CPU.Build.0 = Release|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Release|x64.ActiveCfg = Release|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Release|x64.Build.0 = Release|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|Any CPU.ActiveCfg = Debug|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|Any CPU.Build.0 = Debug|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|x64.ActiveCfg = Debug|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|x64.Build.0 = Debug|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|Any CPU.Build.0 = Release|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|x64.ActiveCfg = Release|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|x64.Build.0 = Release|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|Any CPU.ActiveCfg = Debug|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|Any CPU.Build.0 = Debug|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|x64.ActiveCfg = Debug|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|x64.Build.0 = Debug|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|Any CPU.Build.0 = Release|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|x64.ActiveCfg = Release|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|x64.Build.0 = Release|x64
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|x64.ActiveCfg = Debug|x64
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|x64.Build.0 = Debug|x64
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|Any CPU.Build.0 = Release|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|x64.ActiveCfg = Release|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|x64.Build.0 = Release|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|x64.ActiveCfg = Debug|x64
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|x64.Build.0 = Debug|x64
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|Any CPU.Build.0 = Release|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|x64.ActiveCfg = Release|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|x64.Build.0 = Release|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|x64.ActiveCfg = Debug|x64
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|x64.Build.0 = Debug|x64
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|Any CPU.Build.0 = Release|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|x64.ActiveCfg = Release|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|x64.Build.0 = Release|Any CPU
{F9862446-B144-42F1-87A4-FAF3707268A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F9862446-B144-42F1-87A4-FAF3707268A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9862446-B144-42F1-87A4-FAF3707268A6}.Debug|x64.ActiveCfg = Debug|x64
{F9862446-B144-42F1-87A4-FAF3707268A6}.Debug|x64.Build.0 = Debug|x64
{F9862446-B144-42F1-87A4-FAF3707268A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9862446-B144-42F1-87A4-FAF3707268A6}.Release|Any CPU.Build.0 = Release|Any CPU
{F9862446-B144-42F1-87A4-FAF3707268A6}.Release|x64.ActiveCfg = Release|Any CPU
{F9862446-B144-42F1-87A4-FAF3707268A6}.Release|x64.Build.0 = Release|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|x64.ActiveCfg = Debug|x64
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|x64.Build.0 = Debug|x64
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|Any CPU.Build.0 = Release|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|x64.ActiveCfg = Release|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E} = {2F6173AD-2376-4F42-B852-10E3DBD394EE}
{92834C05-703E-4F05-9224-F36220939D8F} = {CF5B6846-34AF-4FF4-880D-58E34F1134F0}
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD} = {3D5227CE-FAE2-4A56-A303-687DD234FDE2}
{28661E82-C86A-4611-A028-C34F6AC85C97} = {C04CA8B9-5D31-4E8A-9EFD-B1A5AFCEED98}
{B62C822E-701F-480F-BBB1-0E02217D622C} = {C78D0841-72DB-4ED7-B200-2E7F20D9D6BA}
{E07528DD-9DEE-47C2-B79D-235ECFA6B003} = {8AB3E51B-05BE-4C31-9975-8C12CBBF7177}
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF} = {CF5B6846-34AF-4FF4-880D-58E34F1134F0}
{F9862446-B144-42F1-87A4-FAF3707268A6} = {C78D0841-72DB-4ED7-B200-2E7F20D9D6BA}
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892} = {5EB5F581-9DF6-4166-AC5B-89E6851089E9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4C56D4BA-4B41-4AB8-836F-9997506EA9AC}
EndGlobalSection
EndGlobal
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment