添加项目文件。

This commit is contained in:
akwkevin
2021-07-23 09:42:22 +08:00
commit f25a958797
2798 changed files with 352360 additions and 0 deletions

66
.gitattributes vendored Normal file
View File

@@ -0,0 +1,66 @@
*.js linguist-language=csharp
*.css linguist-language=csharp
*.html linguist-language=csharp
###############################################################################
# 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

264
.gitignore vendored Normal file
View File

@@ -0,0 +1,264 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.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
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# 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
# TODO: 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
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable 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
# 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
node_modules/
orleans.codegen.cs
# 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
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# 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/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
/src/Coldairarrow.Web/wwwroot/Upload/File
/src/Coldairarrow.Api/wwwroot/Upload
/.vs/AIStudio.Wpf.Diagram/v16/.suo

View File

@@ -0,0 +1,923 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net472</TargetFrameworks>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Compile Remove="DesignItems\Custom\**" />
<EmbeddedResource Remove="DesignItems\Custom\**" />
<None Remove="DesignItems\Custom\**" />
<Page Remove="DesignItems\Custom\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Controls\AnimationHelper.cs" />
<Compile Remove="Controls\CancelRoutedEventArgs.cs" />
<Compile Remove="Controls\ContextMenuToggleButton.cs" />
<Compile Remove="Controls\ScrollViewer.xaml.cs" />
<Compile Remove="Controls\TabControl.xaml.cs" />
<Compile Remove="Controls\TabItem.cs" />
<Compile Remove="Controls\TabPanel.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="Icons\App.ico" />
<None Remove="Images\AlignObjectsBottom.png" />
<None Remove="Images\AlignObjectsCenteredHorizontal.png" />
<None Remove="Images\AlignObjectsCenteredVertical.png" />
<None Remove="Images\AlignObjectsLeft.png" />
<None Remove="Images\AlignObjectsRight.png" />
<None Remove="Images\AlignObjectsTop.png" />
<None Remove="Images\application_side_boxes.png" />
<None Remove="Images\banner.png" />
<None Remove="Images\Blue.png" />
<None Remove="Images\BlueLarge.png" />
<None Remove="Images\Bold.png" />
<None Remove="Images\Box.png" />
<None Remove="Images\BringForward.png" />
<None Remove="Images\BringToFront.png" />
<None Remove="Images\Brown.png" />
<None Remove="Images\BrownLarge.png" />
<None Remove="Images\ChangeCase.png" />
<None Remove="Images\ClearFormatting.png" />
<None Remove="Images\contactme.png" />
<None Remove="Images\Copy.png" />
<None Remove="Images\Cut.png" />
<None Remove="Images\Delete.png" />
<None Remove="Images\diagram.png" />
<None Remove="Images\Disconnect.png" />
<None Remove="Images\DistributeObjectsHorizontal.png" />
<None Remove="Images\DistributeObjectsVertical.png" />
<None Remove="Images\exit.png" />
<None Remove="Images\FontColor.png" />
<None Remove="Images\FormatPainter.png" />
<None Remove="Images\GalleryLarge.png" />
<None Remove="Images\GenericDocument.png" />
<None Remove="Images\GIF.png" />
<None Remove="Images\Gray.png" />
<None Remove="Images\GrayLarge.png" />
<None Remove="Images\Green.png" />
<None Remove="Images\GreenLarge.png" />
<None Remove="Images\Group.png" />
<None Remove="Images\GrowFont.png" />
<None Remove="Images\help.jpg" />
<None Remove="Images\image.png" />
<None Remove="Images\Italic.png" />
<None Remove="Images\line-dashed.png" />
<None Remove="Images\line-height.png" />
<None Remove="Images\link.png" />
<None Remove="Images\New.png" />
<None Remove="Images\open.png" />
<None Remove="Images\OpenFolder.png" />
<None Remove="Images\Orange.png" />
<None Remove="Images\OrangeLarge.png" />
<None Remove="Images\page_white_stack.png" />
<None Remove="Images\Paste.png" />
<None Remove="Images\PasteBig.png" />
<None Remove="Images\PasteFormating.png" />
<None Remove="Images\PasteImage.png" />
<None Remove="Images\PasteSourceFormating.png" />
<None Remove="Images\PasteText.png" />
<None Remove="Images\PasteTextOnly.png" />
<None Remove="Images\pencil.png" />
<None Remove="Images\Persist.png" />
<None Remove="Images\Pink.png" />
<None Remove="Images\PinkLarge.png" />
<None Remove="Images\Print.png" />
<None Remove="Images\Red.png" />
<None Remove="Images\RedLarge.png" />
<None Remove="Images\redo.png" />
<None Remove="Images\SampleImageForScreenTip.png" />
<None Remove="Images\Save.png" />
<None Remove="Images\saveas.png" />
<None Remove="Images\SendBackward.png" />
<None Remove="Images\SendToBack.png" />
<None Remove="Images\Setting.png" />
<None Remove="Images\ShrinkFont.png" />
<None Remove="Images\Strikethrough.png" />
<None Remove="Images\Subscript.png" />
<None Remove="Images\Superscript.png" />
<None Remove="Images\SVG.png" />
<None Remove="Images\Test16.png" />
<None Remove="Images\Test32.png" />
<None Remove="Images\text.png" />
<None Remove="Images\TextEffects.png" />
<None Remove="Images\TextHighlightColor.png" />
<None Remove="Images\Underline.png" />
<None Remove="Images\undo.png" />
<None Remove="Images\Ungroup.png" />
<None Remove="Images\VIDEO.png" />
<None Remove="Images\Yellow.png" />
<None Remove="Images\YellowLarge.png" />
</ItemGroup>
<ItemGroup>
<Page Remove="Controls\ScrollViewer.xaml" />
<Page Remove="Controls\TabControl.xaml" />
<Page Remove="Images\VectorIcons.xaml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.12" />
<PackageReference Include="MahApps.Metro" Version="2.0.0" />
<PackageReference Include="MahApps.Metro.IconPacks.FontAwesome" Version="4.8.0" />
<PackageReference Include="MahApps.Metro.IconPacks.VaadinIcons" Version="4.8.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Util.Svg2XamlTestExtension" Version="1.2.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Dragablz\Dragablz\Dragablz.csproj" />
<ProjectReference Include="..\Fluent.Ribbon\Fluent.Ribbon\Fluent.Ribbon.csproj" />
<ProjectReference Include="..\gong-wpf-dragdrop\src\GongSolutions.WPF.DragDrop\GongSolutions.WPF.DragDrop.csproj" />
<ProjectReference Include="..\Util.DiagramDesigner\Util.DiagramDesigner.csproj" />
<ProjectReference Include="..\zxing.core\zxing.core\zxing.core.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="Icons\App.ico" />
<Resource Include="Images\AlignObjectsBottom.png" />
<Resource Include="Images\AlignObjectsCenteredHorizontal.png" />
<Resource Include="Images\AlignObjectsCenteredVertical.png" />
<Resource Include="Images\AlignObjectsLeft.png" />
<Resource Include="Images\AlignObjectsRight.png" />
<Resource Include="Images\AlignObjectsTop.png" />
<Resource Include="Images\application_side_boxes.png" />
<Resource Include="Images\banner.png" />
<Resource Include="Images\Blue.png" />
<Resource Include="Images\BlueLarge.png" />
<Resource Include="Images\Bold.png" />
<Resource Include="Images\Box.png" />
<Resource Include="Images\BringForward.png" />
<Resource Include="Images\BringToFront.png" />
<Resource Include="Images\Brown.png" />
<Resource Include="Images\BrownLarge.png" />
<Resource Include="Images\ChangeCase.png" />
<Resource Include="Images\ClearFormatting.png" />
<Resource Include="Images\contactme.png" />
<Resource Include="Images\Copy.png" />
<Resource Include="Images\Cut.png" />
<Resource Include="Images\Delete.png" />
<Resource Include="Images\diagram.png" />
<Resource Include="Images\Disconnect.png" />
<Resource Include="Images\DistributeObjectsHorizontal.png" />
<Resource Include="Images\DistributeObjectsVertical.png" />
<Resource Include="Images\exit.png" />
<Resource Include="Images\FontColor.png" />
<Resource Include="Images\FormatPainter.png" />
<Resource Include="Images\GalleryLarge.png" />
<Resource Include="Images\GenericDocument.png" />
<Resource Include="Images\GIF.png" />
<Resource Include="Images\Gray.png" />
<Resource Include="Images\GrayLarge.png" />
<Resource Include="Images\Green.png" />
<Resource Include="Images\GreenLarge.png" />
<Resource Include="Images\Group.png" />
<Resource Include="Images\GrowFont.png" />
<Resource Include="Images\help.jpg" />
<Resource Include="Images\image.png" />
<Resource Include="Images\Italic.png" />
<Resource Include="Images\line-dashed.png" />
<Resource Include="Images\line-height.png" />
<Resource Include="Images\link.png" />
<Resource Include="Images\New.png" />
<Resource Include="Images\open.png" />
<Resource Include="Images\OpenFolder.png" />
<Resource Include="Images\Orange.png" />
<Resource Include="Images\OrangeLarge.png" />
<Resource Include="Images\page_white_stack.png" />
<Resource Include="Images\Paste.png" />
<Resource Include="Images\PasteBig.png" />
<Resource Include="Images\PasteFormating.png" />
<Resource Include="Images\PasteImage.png" />
<Resource Include="Images\PasteSourceFormating.png" />
<Resource Include="Images\PasteText.png" />
<Resource Include="Images\PasteTextOnly.png" />
<Resource Include="Images\pencil.png" />
<Resource Include="Images\Persist.png" />
<Resource Include="Images\Pink.png" />
<Resource Include="Images\PinkLarge.png" />
<Resource Include="Images\Print.png" />
<Resource Include="Images\Red.png" />
<Resource Include="Images\RedLarge.png" />
<Resource Include="Images\redo.png" />
<Resource Include="Images\SampleImageForScreenTip.png" />
<Resource Include="Images\Save.png" />
<Resource Include="Images\saveas.png" />
<Resource Include="Images\SendBackward.png" />
<Resource Include="Images\SendToBack.png" />
<Resource Include="Images\Setting.png" />
<Resource Include="Images\ShrinkFont.png" />
<Resource Include="Images\Strikethrough.png" />
<Resource Include="Images\Subscript.png" />
<Resource Include="Images\Superscript.png" />
<Resource Include="Images\SVG.png" />
<Resource Include="Images\Test16.png" />
<Resource Include="Images\Test32.png" />
<Resource Include="Images\text.png" />
<Resource Include="Images\TextEffects.png" />
<Resource Include="Images\TextHighlightColor.png" />
<Resource Include="Images\Underline.png" />
<Resource Include="Images\undo.png" />
<Resource Include="Images\Ungroup.png" />
<Resource Include="Images\VectorIcons.xaml">
<Generator>MSBuild:Compile</Generator>
</Resource>
<Resource Include="Images\VIDEO.png" />
<Resource Include="Images\Yellow.png" />
<Resource Include="Images\YellowLarge.png" />
</ItemGroup>
<ItemGroup>
<Page Update="Controls\PopupWindow.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Demos\Logical\ViewModels\LogicalGateItemViewModel.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Demos\Others\ViewModels\BarcodeDesignerItemViewModel.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Demos\Others\ViewModels\PersistDesignerItemViewModel.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Demos\Others\ViewModels\SettingsDesignerItemViewModel.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Demos\Others\ViewModels\OutLineTextDesignerItemViewModel.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
<SubType>Designer</SubType>
</Page>
<Page Update="Demos\Others\ViewModels\PathItemViewModel.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Themes\Generic.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Themes\Shared.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
</ItemGroup>
<ItemGroup>
<None Update="DesignItems\Customs\1.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\account-book.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\alert.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\alipay-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\alipay-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\aliwangwang.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\amazon-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\amazon-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\android.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\api.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\apple.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\appstore.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\audio.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\backward.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\bank.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\behance-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\behance-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\bell.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\book.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\box-plot.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\bug.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\build.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\bulb.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\calculator.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\calendar.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\camera.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\car.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\caret-down.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\caret-left.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\caret-right.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\caret-up.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\carry-out.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\check-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\check-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\chrome.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\ci-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\clock-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\close-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\close-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\cloud.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\code-sandbox-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\code-sandbox-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\code.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\codepen-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\codepen-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\compass.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\contacts.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\container.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\control.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\copy.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\copyright-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\credit-card.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\crown.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\customer-service.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dashboard.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\database.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\delete.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\diff.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dingtalk-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dingtalk-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dislike.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dollar-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\down-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\down-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dribbble-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dribbble-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dropbox-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\dropbox-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\edit.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\environment.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\euro-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\exclamation-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\experiment.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\eye-invisible.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\eye.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\facebook.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\fast-backward.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\fast-forward.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-add.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-excel.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-exclamation.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-image.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-markdown.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-pdf.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-ppt.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-text.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-unknown.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-word.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file-zip.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\file.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\filter.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\fire.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\flag.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\folder-add.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\folder-open.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\folder.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\forward.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\frown.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\fund.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\funnel-plot.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\gift.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\github.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\gitlab.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\golden.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\google-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\google-plus-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\google-plus-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\google-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\hdd.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\heart.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\highlight.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\home.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\hourglass.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\html5.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\idcard.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\ie-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\ie-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\info-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\instagram.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\insurance.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\interaction.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\interation.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\layout.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\left-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\left-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\like.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\linkedin.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\lock.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\mail.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\medicine-box.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\medium-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\medium-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\meh.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\message.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\minus-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\minus-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\mobile.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\money-collect.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\notification.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\pause-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\pay-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\phone.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\picture.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\pie-chart.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\play-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\play-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\plus-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\plus-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\pound-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\printer.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\profile.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\project.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\property-safety.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\pushpin.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\qq-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\qq-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\question-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\read.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\reconciliation.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\red-envelope.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\reddit-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\reddit-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\rest.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\right-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\right-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\rocket.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\safety-certificate.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\save.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\schedule.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\security-scan.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\setting.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\shop.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\shopping.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\sketch-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\sketch-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\skin.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\skype.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\slack-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\slack-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\sliders.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\smile.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\snippets.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\sound.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\star.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\step-backward.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\step-forward.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\stop.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\switcher.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\tablet.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\tag.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\tags.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\taobao-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\taobao-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\thunderbolt.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\tool.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\trademark-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\trophy.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\twitter-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\twitter-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\unlock.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\up-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\up-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\usb.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\video-camera.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\wallet.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\warning.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\wechat.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\weibo-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\weibo-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\windows.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\yahoo.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\youtube.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\yuque.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\zhihu-circle.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Svgs\zhihu-square.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<PropertyGroup>
<LangVersion>8.0</LangVersion>
<ApplicationIcon />
</PropertyGroup>
<ProjectExtensions><VisualStudio><UserProperties designitems_4customs_41_1json__JsonSchema="https://beaujs.com/schema.json" /></VisualStudio></ProjectExtensions>
</Project>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<!--按日期分割日志文件 一天一个-->
<appender name="LogFileAppenderByDate" type="log4net.Appender.RollingFileAppender">
<!--是否续写-->
<param name="AppendToFile" value="true" />
<!--最小锁定模型以允许多个进程可以写入同一个文件-->
<param name="LockingModel" value="log4net.Appender.FileAppender.MinimalLock" />
<param name="StaticLogFileName" value="true" />
<!--保存路径-->
<param name="File" value="Log\" />
<param name="DatePattern" value="yyyy-MM-dd.LOG" />
<param name="StaticLogFileName" value="false" />
<param name="RollingStyle" value="Date" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%n-----------------------------------------%n时间:%d %n级别:%level %n类名:%c%n文件:%F 第%L行%n日志内容:%m%n-----------------------------------------%n%n" />
</layout>
</appender>
<root>
<!--文件形式记录日志-->
<appender-ref ref="LogFileAppenderByDate" />
</root>
</log4net>
</configuration>

View File

@@ -0,0 +1,15 @@
<Application x:Class="AIStudio.Wpf.ADiagram.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AIStudio.Wpf.ADiagram"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Fluent;component/Themes/Generic.xaml" />
<ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/Generic.xaml" />
<ResourceDictionary Source="/AIStudio.Wpf.ADiagram;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
//注意下面的语句一定要加上指定log4net使用.config文件来读取配置信息
//如果是WinForm假定程序为MyDemo.exe则需要一个MyDemo.exe.config文件
//如果是WebForm则从web.config中读取相关信息
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace AIStudio.Wpf.ADiagram
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public App()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Application.Current.DispatcherUnhandledException += Application_DispatcherUnhandledException;
}
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
//记录严重错误
log.Fatal(e.Exception);
e.Handled = true;//使用这一行代码告诉运行时该异常被处理了不再作为UnhandledException抛出了。
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
//记录严重错误
log.Fatal(e.ExceptionObject);
}
}
}

View File

@@ -0,0 +1,82 @@
using AIStudio.Wpf.ADiagram.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram
{
/// <summary>
/// Simple service interface
/// </summary>
public interface IServiceProvider
{
IUIVisualizerService VisualizerService { get; }
IMessageBoxService MessageBoxService { get; }
//IDatabaseAccessService DatabaseAccessService { get; }
}
/// <summary>
/// Simple service locator
/// </summary>
public class ServiceProvider : IServiceProvider
{
private IUIVisualizerService visualizerService = new WPFUIVisualizerService();
private IMessageBoxService messageBoxService = new WPFMessageBoxService();
//private IDatabaseAccessService databaseAccessService = new DatabaseAccessService();
public IUIVisualizerService VisualizerService
{
get { return visualizerService; }
}
public IMessageBoxService MessageBoxService
{
get { return messageBoxService; }
}
//public IDatabaseAccessService DatabaseAccessService
//{
// get { return databaseAccessService; }
//}
}
/// <summary>
/// Simple service locator helper
/// </summary>
public class ApplicationServicesProvider
{
private static Lazy<ApplicationServicesProvider> instance = new Lazy<ApplicationServicesProvider>(() => new ApplicationServicesProvider());
private IServiceProvider serviceProvider = new ServiceProvider();
private ApplicationServicesProvider()
{
}
static ApplicationServicesProvider()
{
}
public void SetNewServiceProvider(IServiceProvider provider)
{
serviceProvider = provider;
}
public IServiceProvider Provider
{
get { return serviceProvider; }
}
public static ApplicationServicesProvider Instance
{
get { return instance.Value; }
}
}
}

View File

@@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@@ -0,0 +1,908 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace AIStudio.Wpf.ADiagram.Commands
{
/// <summary>
/// This class allows delegating the commanding logic to methods passed as parameters,
/// and enables a View to bind commands to objects that are not part of the element tree.
/// </summary>
public class CanExecuteDelegateCommand : IDelegateCommand
{
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action executeMethod)
: this(executeMethod, null, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
: this(executeMethod, canExecuteMethod, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
{
if (executeMethod == null)
{
throw new ArgumentNullException("executeMethod");
}
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
}
#endregion
#region Public Methods
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute()
{
if (_canExecuteMethod != null)
{
return _canExecuteMethod();
}
return true;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute()
{
if (_executeMethod != null)
{
_executeMethod();
}
}
/// <summary>
///
/// </summary>
public object Target
{
get
{
if (_executeMethod == null)
return null;
return _executeMethod.Target;
}
}
/// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled
{
get
{
return _isAutomaticRequeryDisabled;
}
set
{
if (_isAutomaticRequeryDisabled != value)
{
if (value)
{
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
}
else
{
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
}
_isAutomaticRequeryDisabled = value;
}
}
}
/// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
/// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
}
#endregion
#region ICommand Members
/// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested += value;
}
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
}
remove
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested -= value;
}
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute();
}
void ICommand.Execute(object parameter)
{
Execute();
}
#endregion
#region Data
private readonly Action _executeMethod = null;
private readonly Func<bool> _canExecuteMethod = null;
private bool _isAutomaticRequeryDisabled = false;
private List<WeakReference> _canExecuteChangedHandlers;
#endregion
}
public class CanExecuteDelegateCommand<T1> : IDelegateCommand
{
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1> executeMethod)
: this(executeMethod, null, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1> executeMethod, Func<T1, bool> canExecuteMethod)
: this(executeMethod, canExecuteMethod, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1> executeMethod, Func<T1, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
{
if (executeMethod == null)
{
throw new ArgumentNullException("executeMethod");
}
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
}
#endregion
#region Public Methods
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute(T1 parameter1)
{
if (_canExecuteMethod != null)
{
return _canExecuteMethod(parameter1);
}
return true;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute(T1 parameter1)
{
if (_executeMethod != null)
{
_executeMethod(parameter1);
}
}
/// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
/// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
}
/// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled
{
get
{
return _isAutomaticRequeryDisabled;
}
set
{
if (_isAutomaticRequeryDisabled != value)
{
if (value)
{
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
}
else
{
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
}
_isAutomaticRequeryDisabled = value;
}
}
}
/// <summary>
///
/// </summary>
public object Target
{
get
{
if (_executeMethod == null)
return null;
return _executeMethod.Target;
}
}
#endregion
#region ICommand Members
/// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested += value;
}
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
}
remove
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested -= value;
}
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
}
public virtual bool CanExecute(object parameter)
{
if (parameter == null || (parameter is object[] && (parameter as object[]).Length < 1))
return false;
if (parameter is object[])
{
object[] parameters = parameter as object[];
// if T is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|| (parameters[0] == null && typeof(T1).IsValueType)
)
{
return false;
}
return CanExecute((T1)parameters[0]);
}
else
{
if (parameter != null && !typeof(T1).IsAssignableFrom(parameter.GetType()))
parameter = null;
return CanExecute((T1)parameter);
}
}
public virtual void Execute(object parameter)
{
//如果T1不允许为空而parameter参数又为空则直接返回
if (typeof(T1).IsValueType && (parameter == null || (parameter is object[] && (parameter as object[]).Length < 1)))
return;
if (parameter is object[])
{
object[] parameters = parameter as object[];
// if T1 is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|| (parameters[0] == null && typeof(T1).IsValueType)
)
return;
Execute((T1)parameters[0]);
}
else
{
if (parameter != null && !typeof(T1).IsAssignableFrom(parameter.GetType()))
parameter = null;
Execute((T1)parameter);
}
}
#endregion
#region Data
private readonly Action<T1> _executeMethod = null;
private readonly Func<T1, bool> _canExecuteMethod = null;
private bool _isAutomaticRequeryDisabled = false;
private List<WeakReference> _canExecuteChangedHandlers;
#endregion
}
public class CanExecuteDelegateCommand<T1, T2> : IDelegateCommand
{
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1, T2> executeMethod)
: this(executeMethod, null, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1, T2> executeMethod, Func<T1, T2, bool> canExecuteMethod)
: this(executeMethod, canExecuteMethod, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1, T2> executeMethod, Func<T1, T2, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
{
if (executeMethod == null)
{
throw new ArgumentNullException("executeMethod");
}
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
}
#endregion
#region Public Methods
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute(T1 parameter1, T2 parameter2)
{
if (_canExecuteMethod != null)
{
return _canExecuteMethod(parameter1, parameter2);
}
return true;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute(T1 parameter1, T2 parameter2)
{
if (_executeMethod != null)
{
_executeMethod(parameter1, parameter2);
}
}
/// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
/// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
}
/// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled
{
get
{
return _isAutomaticRequeryDisabled;
}
set
{
if (_isAutomaticRequeryDisabled != value)
{
if (value)
{
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
}
else
{
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
}
_isAutomaticRequeryDisabled = value;
}
}
}
/// <summary>
///
/// </summary>
public object Target
{
get
{
if (_executeMethod == null)
return null;
return _executeMethod.Target;
}
}
#endregion
#region ICommand Members
/// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested += value;
}
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
}
remove
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested -= value;
}
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
}
public virtual bool CanExecute(object parameter)
{
if (parameter == null || !(parameter is object[]) || (parameter as object[]).Length < 2)
return false;
object[] parameters = parameter as object[];
// if T is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|| (parameters[0] == null && typeof(T1).IsValueType)
|| (parameters[1] != null && !typeof(T2).IsAssignableFrom(parameters[1].GetType()))
|| (parameters[1] == null && typeof(T2).IsValueType)
)
{
return false;
}
return CanExecute((T1)parameters[0], (T2)parameters[1]);
}
public virtual void Execute(object parameter)
{
if (parameter == null || !(parameter is object[]) || (parameter as object[]).Length < 2)
return;
object[] parameters = parameter as object[];
// if T is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|| (parameters[0] == null && typeof(T1).IsValueType)
|| (parameters[1] != null && !typeof(T2).IsAssignableFrom(parameters[1].GetType()))
|| (parameters[1] == null && typeof(T2).IsValueType)
)
return;
Execute((T1)parameters[0], (T2)parameters[1]);
}
#endregion
#region Data
private readonly Action<T1, T2> _executeMethod = null;
private readonly Func<T1, T2, bool> _canExecuteMethod = null;
private bool _isAutomaticRequeryDisabled = false;
private List<WeakReference> _canExecuteChangedHandlers;
#endregion
}
public class CanExecuteDelegateCommand<T1, T2, T3> : IDelegateCommand
{
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1, T2, T3> executeMethod)
: this(executeMethod, null, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1, T2, T3> executeMethod, Func<T1, T2, T3, bool> canExecuteMethod)
: this(executeMethod, canExecuteMethod, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public CanExecuteDelegateCommand(Action<T1, T2, T3> executeMethod, Func<T1, T2, T3, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
{
if (executeMethod == null)
{
throw new ArgumentNullException("executeMethod");
}
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
}
#endregion
#region Public Methods
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute(T1 parameter1, T2 parameter2, T3 parameter3)
{
if (_canExecuteMethod != null)
{
return _canExecuteMethod(parameter1, parameter2, parameter3);
}
return true;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute(T1 parameter1, T2 parameter2, T3 parameter3)
{
if (_executeMethod != null)
{
_executeMethod(parameter1, parameter2, parameter3);
}
}
/// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
/// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
}
/// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled
{
get
{
return _isAutomaticRequeryDisabled;
}
set
{
if (_isAutomaticRequeryDisabled != value)
{
if (value)
{
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
}
else
{
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
}
_isAutomaticRequeryDisabled = value;
}
}
}
/// <summary>
///
/// </summary>
public object Target
{
get
{
if (_executeMethod == null)
return null;
return _executeMethod.Target;
}
}
#endregion
#region ICommand Members
/// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested += value;
}
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
}
remove
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested -= value;
}
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
}
public virtual bool CanExecute(object parameter)
{
if (parameter == null || !(parameter is object[]) || (parameter as object[]).Length < 3)
return false;
object[] parameters = parameter as object[];
// if T is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|| (parameters[0] == null && typeof(T1).IsValueType)
|| (parameters[1] != null && !typeof(T2).IsAssignableFrom(parameters[1].GetType()))
|| (parameters[1] == null && typeof(T2).IsValueType)
|| (parameters[2] != null && !typeof(T3).IsAssignableFrom(parameters[2].GetType()))
|| (parameters[2] == null && typeof(T3).IsValueType)
)
{
return false;
}
return CanExecute((T1)parameters[0], (T2)parameters[1], (T3)parameters[2]);
}
public virtual void Execute(object parameter)
{
if (parameter == null || !(parameter is object[]) || (parameter as object[]).Length < 3)
return;
object[] parameters = parameter as object[];
// if T is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|| (parameters[0] == null && typeof(T1).IsValueType)
|| (parameters[1] != null && !typeof(T2).IsAssignableFrom(parameters[1].GetType()))
|| (parameters[1] == null && typeof(T2).IsValueType)
|| (parameters[2] != null && !typeof(T3).IsAssignableFrom(parameters[2].GetType()))
|| (parameters[2] == null && typeof(T3).IsValueType)
)
return;
Execute((T1)parameters[0], (T2)parameters[1], (T3)parameters[2]);
}
#endregion
#region Data
private readonly Action<T1, T2, T3> _executeMethod = null;
private readonly Func<T1, T2, T3, bool> _canExecuteMethod = null;
private bool _isAutomaticRequeryDisabled = false;
private List<WeakReference> _canExecuteChangedHandlers;
#endregion
}
public interface IDelegateCommand : ICommand
{
object Target { get; }
}
/// <summary>
/// This class contains methods for the CommandManager that help avoid memory leaks by
/// using weak references.
/// </summary>
internal class CommandManagerHelper
{
internal static void CallWeakReferenceHandlers(List<WeakReference> handlers)
{
if (handlers != null)
{
// Take a snapshot of the handlers before we call out to them since the handlers
// could cause the array to me modified while we are reading it.
EventHandler[] callees = new EventHandler[handlers.Count];
int count = 0;
for (int i = handlers.Count - 1; i >= 0; i--)
{
WeakReference reference = handlers[i];
EventHandler handler = reference.Target as EventHandler;
if (handler == null)
{
// Clean up old handlers that have been collected
handlers.RemoveAt(i);
}
else
{
callees[count] = handler;
count++;
}
}
// Call the handlers that we snapshotted
for (int i = 0; i < count; i++)
{
EventHandler handler = callees[i];
handler(null, EventArgs.Empty);
}
}
}
internal static void AddHandlersToRequerySuggested(List<WeakReference> handlers)
{
if (handlers != null)
{
foreach (WeakReference handlerRef in handlers)
{
EventHandler handler = handlerRef.Target as EventHandler;
if (handler != null)
{
CommandManager.RequerySuggested += handler;
}
}
}
}
internal static void RemoveHandlersFromRequerySuggested(List<WeakReference> handlers)
{
if (handlers != null)
{
foreach (WeakReference handlerRef in handlers)
{
EventHandler handler = handlerRef.Target as EventHandler;
if (handler != null)
{
CommandManager.RequerySuggested -= handler;
}
}
}
}
internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler)
{
AddWeakReferenceHandler(ref handlers, handler, -1);
}
internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize)
{
if (handlers == null)
{
handlers = (defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>());
}
handlers.Add(new WeakReference(handler));
}
internal static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler)
{
if (handlers != null)
{
for (int i = handlers.Count - 1; i >= 0; i--)
{
WeakReference reference = handlers[i];
EventHandler existingHandler = reference.Target as EventHandler;
if ((existingHandler == null) || (existingHandler == handler))
{
// Clean up old handlers that have been collected
// in addition to the handler that is to be removed.
handlers.RemoveAt(i);
}
}
}
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace AIStudio.Wpf.ADiagram.Commands
{
public class CommandReference : Freezable, ICommand
{
public CommandReference()
{
// Blank
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandReference), new PropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
#region ICommand Members
public bool CanExecute(object parameter)
{
if (Command != null)
return Command.CanExecute(parameter);
return false;
}
public void Execute(object parameter)
{
Command.Execute(parameter);
}
public event EventHandler CanExecuteChanged;
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandReference commandReference = d as CommandReference;
ICommand oldCommand = e.OldValue as ICommand;
ICommand newCommand = e.NewValue as ICommand;
if (oldCommand != null)
{
oldCommand.CanExecuteChanged -= commandReference.CanExecuteChanged;
}
if (newCommand != null)
{
newCommand.CanExecuteChanged += commandReference.CanExecuteChanged;
}
}
#endregion
#region Freezable
protected override Freezable CreateInstanceCore()
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@@ -0,0 +1,240 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows.Input;
namespace AIStudio.Wpf.ADiagram.Commands
{
/// <summary>
/// The CompositeCommand composes one or more ICommands.
/// </summary>
public class CompositeCommand : ICommand
{
private readonly List<ICommand> _registeredCommands = new List<ICommand>();
private readonly bool _monitorCommandActivity;
private readonly EventHandler _onRegisteredCommandCanExecuteChangedHandler;
private SynchronizationContext _synchronizationContext;
/// <summary>
/// Initializes a new instance of <see cref="CompositeCommand"/>.
/// </summary>
public CompositeCommand()
{
this._onRegisteredCommandCanExecuteChangedHandler = new EventHandler(this.OnRegisteredCommandCanExecuteChanged);
_synchronizationContext = SynchronizationContext.Current;
}
/// <summary>
/// Initializes a new instance of <see cref="CompositeCommand"/>.
/// </summary>
/// <param name="monitorCommandActivity">Indicates when the command activity is going to be monitored.</param>
public CompositeCommand(bool monitorCommandActivity)
: this()
{
this._monitorCommandActivity = monitorCommandActivity;
}
/// <summary>
/// Adds a command to the collection and signs up for the <see cref="ICommand.CanExecuteChanged"/> event of it.
/// </summary>
/// <remarks>
/// If this command is set to monitor command activity, and <paramref name="command"/>
/// implements the <see cref="IActiveAware"/> interface, this method will subscribe to its
/// <see cref="IActiveAware.IsActiveChanged"/> event.
/// </remarks>
/// <param name="command">The command to register.</param>
public virtual void RegisterCommand(ICommand command)
{
if (command == null) throw new ArgumentNullException(nameof(command));
if (command == this)
{
throw new ArgumentException("CannotRegisterCompositeCommandInItself");
}
lock (this._registeredCommands)
{
if (this._registeredCommands.Contains(command))
{
throw new InvalidOperationException("CannotRegisterSameCommandTwice");
}
this._registeredCommands.Add(command);
}
command.CanExecuteChanged += this._onRegisteredCommandCanExecuteChangedHandler;
this.OnCanExecuteChanged();
if (this._monitorCommandActivity)
{
var activeAwareCommand = command as IActiveAware;
if (activeAwareCommand != null)
{
activeAwareCommand.IsActiveChanged += this.Command_IsActiveChanged;
}
}
}
/// <summary>
/// Removes a command from the collection and removes itself from the <see cref="ICommand.CanExecuteChanged"/> event of it.
/// </summary>
/// <param name="command">The command to unregister.</param>
public virtual void UnregisterCommand(ICommand command)
{
if (command == null) throw new ArgumentNullException(nameof(command));
bool removed;
lock (this._registeredCommands)
{
removed = this._registeredCommands.Remove(command);
}
if (removed)
{
command.CanExecuteChanged -= this._onRegisteredCommandCanExecuteChangedHandler;
this.OnCanExecuteChanged();
if (this._monitorCommandActivity)
{
var activeAwareCommand = command as IActiveAware;
if (activeAwareCommand != null)
{
activeAwareCommand.IsActiveChanged -= this.Command_IsActiveChanged;
}
}
}
}
private void OnRegisteredCommandCanExecuteChanged(object sender, EventArgs e)
{
this.OnCanExecuteChanged();
}
/// <summary>
/// Forwards <see cref="ICommand.CanExecute"/> to the registered commands and returns
/// <see langword="true" /> if all of the commands return <see langword="true" />.
/// </summary>
/// <param name="parameter">Data used by the command.
/// If the command does not require data to be passed, this object can be set to <see langword="null" />.
/// </param>
/// <returns><see langword="true" /> if all of the commands return <see langword="true" />; otherwise, <see langword="false" />.</returns>
public virtual bool CanExecute(object parameter)
{
bool hasEnabledCommandsThatShouldBeExecuted = false;
ICommand[] commandList;
lock (this._registeredCommands)
{
commandList = this._registeredCommands.ToArray();
}
foreach (ICommand command in commandList)
{
if (this.ShouldExecute(command))
{
if (!command.CanExecute(parameter))
{
return false;
}
hasEnabledCommandsThatShouldBeExecuted = true;
}
}
return hasEnabledCommandsThatShouldBeExecuted;
}
/// <summary>
/// Occurs when any of the registered commands raise <see cref="ICommand.CanExecuteChanged"/>.
/// </summary>
public virtual event EventHandler CanExecuteChanged;
/// <summary>
/// Forwards <see cref="ICommand.Execute"/> to the registered commands.
/// </summary>
/// <param name="parameter">Data used by the command.
/// If the command does not require data to be passed, this object can be set to <see langword="null" />.
/// </param>
public virtual void Execute(object parameter)
{
Queue<ICommand> commands;
lock (this._registeredCommands)
{
commands = new Queue<ICommand>(this._registeredCommands.Where(this.ShouldExecute).ToList());
}
while (commands.Count > 0)
{
ICommand command = commands.Dequeue();
command.Execute(parameter);
}
}
/// <summary>
/// Evaluates if a command should execute.
/// </summary>
/// <param name="command">The command to evaluate.</param>
/// <returns>A <see cref="bool"/> value indicating whether the command should be used
/// when evaluating <see cref="CompositeCommand.CanExecute"/> and <see cref="CompositeCommand.Execute"/>.</returns>
/// <remarks>
/// If this command is set to monitor command activity, and <paramref name="command"/>
/// implements the <see cref="IActiveAware"/> interface,
/// this method will return <see langword="false" /> if the command's <see cref="IActiveAware.IsActive"/>
/// property is <see langword="false" />; otherwise it always returns <see langword="true" />.</remarks>
protected virtual bool ShouldExecute(ICommand command)
{
var activeAwareCommand = command as IActiveAware;
if (this._monitorCommandActivity && activeAwareCommand != null)
{
return activeAwareCommand.IsActive;
}
return true;
}
/// <summary>
/// Gets the list of all the registered commands.
/// </summary>
/// <value>A list of registered commands.</value>
/// <remarks>This returns a copy of the commands subscribed to the CompositeCommand.</remarks>
public IList<ICommand> RegisteredCommands
{
get
{
IList<ICommand> commandList;
lock (this._registeredCommands)
{
commandList = this._registeredCommands.ToList();
}
return commandList;
}
}
/// <summary>
/// Raises <see cref="ICommand.CanExecuteChanged"/> on the UI thread so every
/// command invoker can requery <see cref="ICommand.CanExecute"/> to check if the
/// <see cref="CompositeCommand"/> can execute.
/// </summary>a
protected virtual void OnCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
if (_synchronizationContext != null && _synchronizationContext != SynchronizationContext.Current)
_synchronizationContext.Post((o) => handler.Invoke(this, EventArgs.Empty), null);
else
handler.Invoke(this, EventArgs.Empty);
}
}
/// <summary>
/// Handler for IsActiveChanged events of registered commands.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">EventArgs to pass to the event.</param>
private void Command_IsActiveChanged(object sender, EventArgs e)
{
this.OnCanExecuteChanged();
}
}
}

View File

@@ -0,0 +1,334 @@
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
namespace AIStudio.Wpf.ADiagram.Commands
{
[MarkupExtensionReturnType(typeof(object))]
public class ControlBinding : MarkupExtension
{
/// <summary>
/// 是否禁止处理绑定
/// </summary>
public static bool Disabled = false;
#region Properties
public IValueConverter Converter { get; set; }
public object ConverterParameter { get; set; }
public string ElementName { get; set; }
public RelativeSource RelativeSource { get; set; }
public object Source { get; set; }
public bool ValidatesOnDataErrors { get; set; }
public bool ValidatesOnExceptions { get; set; }
public bool NotifyOnValidationError { get; set; }
public object TargetNullValue { get; set; }
public object FallBackValue { get; set; }
public string StringFormat { get; set; }
public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
public Collection<ValidationRule> ValidationRules { get; set; }
public BindingMode Mode { get; set; }
private int AncestorLevel = 1;
[ConstructorArgument("path")]
public PropertyPath Path { get; set; }
[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
public CultureInfo ConverterCulture { get; set; }
#endregion
public ControlBinding()
{
Mode = BindingMode.Default;
ValidationRules = new Collection<ValidationRule>();
}
public ControlBinding(PropertyPath path)
{
Path = path;
Mode = BindingMode.Default;
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
NotifyOnValidationError = true;
ValidatesOnDataErrors = true;
ValidatesOnExceptions = true;
TargetNullValue = null;
ValidationRules = new Collection<ValidationRule>();
}
public ControlBinding(PropertyPath path, string elementName)
: this(path)
{
Path = path;
if (elementName == "$")
AncestorLevel = 2;
else
ElementName = elementName;
}
/// <summary>
/// 获取代理Binding对象
/// </summary>
/// <returns></returns>
internal Binding GetBinding(object rootObject)
{
Binding binding = new Binding();
binding.StringFormat = StringFormat;
binding.Path = Path;
binding.Mode = Mode;
binding.Converter = Converter;
binding.ConverterCulture = ConverterCulture;
binding.ConverterParameter = ConverterParameter;
binding.UpdateSourceTrigger = UpdateSourceTrigger;
if (TargetNullValue != null) binding.TargetNullValue = TargetNullValue;
if (FallBackValue != null)
binding.FallbackValue = FallBackValue;
//单向绑定不需要进行数据校验
NotifyOnValidationError &= (Mode != BindingMode.OneWay && Mode != BindingMode.OneTime);
binding.ValidatesOnDataErrors = NotifyOnValidationError;
binding.ValidatesOnExceptions = NotifyOnValidationError;
binding.NotifyOnValidationError = NotifyOnValidationError;
//添加ValidationRule
foreach (ValidationRule vr in ValidationRules)
binding.ValidationRules.Add(vr);
if (ElementName != null)
binding.ElementName = ElementName;
if (Source != null)
{
if (!(Source is string) || (Source as string) != "$")
binding.Source = Source;
}
if (RelativeSource != null)
binding.RelativeSource = RelativeSource;
if (string.IsNullOrEmpty(ElementName) && Source == null && RelativeSource == null)
{
if (rootObject == null)
{
RelativeSource = new RelativeSource { AncestorLevel = AncestorLevel, AncestorType = typeof(UserControl), Mode = RelativeSourceMode.FindAncestor };
binding.RelativeSource = RelativeSource;
}
else
{
binding.Source = rootObject;
if (rootObject is UserControl || rootObject is Window)
{
if (binding.Path == null || binding.Path.Path == ".")
binding.Path = new PropertyPath("DataContext");
else
binding.Path = new PropertyPath("DataContext." + binding.Path.Path, binding.Path.PathParameters);
}
}
}
return binding;
}
public override object ProvideValue(System.IServiceProvider serviceProvider)
{
var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (valueProvider == null)
return null;
//当使用ControlMultiBinding或者MultiBinding时
if (valueProvider.TargetProperty == null && valueProvider.TargetObject is ICollection)
{
if (valueProvider.TargetObject is Collection<ControlBinding>
|| valueProvider.TargetObject.GetType().FullName == "MS.Internal.Data.BindingCollection")
return this;
}
//如果禁用
if (ControlBinding.Disabled)
return (valueProvider.TargetProperty as DependencyProperty).DefaultMetadata.DefaultValue;
var rootObjProvider = serviceProvider.GetService(typeof(System.Xaml.IRootObjectProvider)) as System.Xaml.IRootObjectProvider;
#region WinForm的ControlBinding
if (valueProvider.TargetObject is System.Windows.Forms.Control && rootObjProvider != null)
{
System.Windows.Forms.Control ctl = valueProvider.TargetObject as System.Windows.Forms.Control;
System.Windows.Forms.Binding b = new System.Windows.Forms.Binding((valueProvider.TargetProperty as PropertyInfo).Name, rootObjProvider.RootObject, Path.Path);
if (Mode == BindingMode.OneWay)
{
b.ControlUpdateMode = System.Windows.Forms.ControlUpdateMode.OnPropertyChanged;
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.Never;
}
else if (Mode == BindingMode.OneWayToSource)
{
b.ControlUpdateMode = System.Windows.Forms.ControlUpdateMode.Never;
if (UpdateSourceTrigger == System.Windows.Data.UpdateSourceTrigger.PropertyChanged
|| UpdateSourceTrigger == System.Windows.Data.UpdateSourceTrigger.Default)
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged;
else if (UpdateSourceTrigger == System.Windows.Data.UpdateSourceTrigger.LostFocus)
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.OnValidation;
}
else if (Mode == BindingMode.TwoWay || Mode == BindingMode.Default)
{
b.ControlUpdateMode = System.Windows.Forms.ControlUpdateMode.OnPropertyChanged;
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged;
}
else if (Mode == BindingMode.OneTime)
{
//这里应该赋值一次:OneTime
//......
b.ControlUpdateMode = System.Windows.Forms.ControlUpdateMode.Never;
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.Never;
}
ctl.DataBindings.Add(b);
return null;
}
#endregion
var bindingTarget = valueProvider.TargetObject as DependencyObject;
var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
if (bindingProperty == null)
return null;
#region 使Binding返回最终的值
//得到Binding对象
Binding binding = GetBinding(rootObjProvider == null ? null : rootObjProvider.RootObject);
if (binding == null) return null;
object retValue = binding.ProvideValue(serviceProvider);
#endregion
return retValue;
}
}
[ContentProperty("Bindings")]
public class ControlMultiBinding : MarkupExtension
{
#region Properties
public Collection<ControlBinding> Bindings { get; private set; }
public IMultiValueConverter Converter { get; set; }
[DefaultValue("")]
[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
public CultureInfo ConverterCulture { get; set; }
[DefaultValue("")]
public object ConverterParameter { get; set; }
public BindingMode Mode { get; set; }
[DefaultValue(false)]
public bool NotifyOnSourceUpdated { get; set; }
[DefaultValue(false)]
public bool NotifyOnTargetUpdated { get; set; }
[DefaultValue(false)]
public bool NotifyOnValidationError { get; set; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter { get; set; }
public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
[DefaultValue(false)]
public bool ValidatesOnDataErrors { get; set; }
[DefaultValue(false)]
public bool ValidatesOnExceptions { get; set; }
public Collection<ValidationRule> ValidationRules { get; private set; }
#endregion
public ControlMultiBinding()
{
Bindings = new Collection<ControlBinding>();
ValidationRules = new Collection<ValidationRule>();
Mode = BindingMode.Default;
UpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.Default;
}
/// <summary>
/// 获取代理MultiBindings对象
/// </summary>
/// <returns></returns>
internal MultiBinding GetMultiBindings(object rootObject)
{
MultiBinding multiBindings = new MultiBinding();
if (this.Converter != null)
multiBindings.Converter = this.Converter;
if (this.ConverterCulture != null)
multiBindings.ConverterCulture = this.ConverterCulture;
if (this.ConverterParameter != null)
multiBindings.ConverterParameter = this.ConverterParameter;
if (this.UpdateSourceExceptionFilter != null)
multiBindings.UpdateSourceExceptionFilter = this.UpdateSourceExceptionFilter;
multiBindings.Mode = this.Mode;
multiBindings.NotifyOnSourceUpdated = this.NotifyOnSourceUpdated;
multiBindings.NotifyOnTargetUpdated = this.NotifyOnTargetUpdated;
multiBindings.NotifyOnValidationError = this.NotifyOnValidationError;
multiBindings.UpdateSourceTrigger = this.UpdateSourceTrigger;
multiBindings.ValidatesOnDataErrors = this.ValidatesOnDataErrors;
multiBindings.ValidatesOnExceptions = this.ValidatesOnExceptions;
foreach (object bd in Bindings)
{
if (bd is BindingBase)
multiBindings.Bindings.Add(bd as BindingBase);
else if (bd is ControlBinding)
multiBindings.Bindings.Add((bd as ControlBinding).GetBinding(rootObject) as BindingBase);
}
foreach (ValidationRule vr in ValidationRules)
multiBindings.ValidationRules.Add(vr);
return multiBindings;
}
public override object ProvideValue(System.IServiceProvider serviceProvider)
{
var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (valueProvider == null)
return null;
var bindingTarget = valueProvider.TargetObject as DependencyObject;
var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
if (bindingProperty == null)
return null;
//使用MultiBindings返回最终的值
#region 使Binding返回最终的值
var rootObjProvider = serviceProvider.GetService(typeof(System.Xaml.IRootObjectProvider)) as System.Xaml.IRootObjectProvider;
MultiBinding multiBindings = GetMultiBindings(rootObjProvider == null ? null : rootObjProvider.RootObject);
if (multiBindings == null) return null;
object retValue = multiBindings.ProvideValue(serviceProvider);
#endregion
return retValue;
}
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace AIStudio.Wpf.ADiagram.Commands
{
#region ConbrolCommand
public interface IControlCommand
{
void SetControl(Control cb);
void SetBase(IControlCommand cc);
void Execute(object parameter);
}
/// <summary>
/// ControlBase可以使用的命令类
/// 使用此类可以使Command具有继承的机制在新的Command中可以调用旧的Command
/// </summary>
public class ControlCommand<T1> : CanExecuteDelegateCommand<ControlCommand<T1>, T1>, IControlCommand
{
public Control Control { get; protected set; }
public IControlCommand Base { get; protected set; }
public string Name { get; set; }
public ControlCommand(Action<ControlCommand<T1>, T1> executeMethod, Func<ControlCommand<T1>, T1, bool> canExecuteMethod = null, bool isAutomaticRequeryDisabled = false, string name = "")
: base(executeMethod, canExecuteMethod, isAutomaticRequeryDisabled)
{
Name = name;
}
public override bool CanExecute(object parameter)
{
return base.CanExecute(new object[] { this, parameter });
}
public override void Execute(object parameter)
{
base.Execute(new object[] { this, parameter });
}
public virtual void ExecuteBaseCommand(T1 parameter)
{
if (Base != null)
Base.Execute((object)parameter);
}
public void SetControl(Control cb)
{
Control = cb;
}
public void SetBase(IControlCommand cc)
{
Base = cc;
}
}
public class ControlCommand : CanExecuteDelegateCommand<ControlCommand>, IControlCommand
{
public Control Control { get; protected set; }
public IControlCommand Base { get; protected set; }
public string Name { get; set; }
public ControlCommand(Action<ControlCommand> executeMethod, Func<ControlCommand, bool> canExecuteMethod = null, bool isAutomaticRequeryDisabled = false, string name = "")
: base(executeMethod, canExecuteMethod, isAutomaticRequeryDisabled)
{
Name = name;
}
public override bool CanExecute(object parameter)
{
return base.CanExecute(new object[] { this });
}
public override void Execute(object parameter)
{
base.Execute(new object[] { this });
}
public virtual void ExecuteBaseCommand()
{
if (Base != null)
Base.Execute((object)null);
}
public void SetControl(Control cb)
{
Control = cb;
}
public void SetBase(IControlCommand cc)
{
Base = cc;
}
}
#endregion
}

View File

@@ -0,0 +1,140 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Windows.Input;
namespace AIStudio.Wpf.ADiagram.Commands
{
/// <summary>
/// An <see cref="ICommand"/> whose delegates can be attached for <see cref="Execute(T)"/> and <see cref="CanExecute(T)"/>.
/// </summary>
/// <typeparam name="T">Parameter type.</typeparam>
/// <remarks>
/// The constructor deliberately prevents the use of value types.
/// Because ICommand takes an object, having a value type for T would cause unexpected behavior when CanExecute(null) is called during XAML initialization for command bindings.
/// Using default(T) was considered and rejected as a solution because the implementor would not be able to distinguish between a valid and defaulted values.
/// <para/>
/// Instead, callers should support a value type by using a nullable value type and checking the HasValue property before using the Value property.
/// <example>
/// <code>
/// public MyClass()
/// {
/// this.submitCommand = new DelegateCommand&lt;int?&gt;(this.Submit, this.CanSubmit);
/// }
///
/// private bool CanSubmit(int? customerId)
/// {
/// return (customerId.HasValue &amp;&amp; customers.Contains(customerId.Value));
/// }
/// </code>
/// </example>
/// </remarks>
public class DelegateCommand<T> : DelegateCommandBase
{
readonly Action<T> _executeMethod;
Func<T, bool> _canExecuteMethod;
/// <summary>
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
/// </summary>
/// <param name="executeMethod">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
/// <remarks><see cref="CanExecute(T)"/> will always return true.</remarks>
public DelegateCommand(Action<T> executeMethod)
: this(executeMethod, (o) => true)
{
}
/// <summary>
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
/// </summary>
/// <param name="executeMethod">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
/// <param name="canExecuteMethod">Delegate to execute when CanExecute is called on the command. This can be null.</param>
/// <exception cref="ArgumentNullException">When both <paramref name="executeMethod"/> and <paramref name="canExecuteMethod"/> are <see langword="null" />.</exception>
public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
: base()
{
if (executeMethod == null || canExecuteMethod == null)
throw new ArgumentNullException(nameof(executeMethod), "DelegateCommandDelegatesCannotBeNull");
TypeInfo genericTypeInfo = typeof(T).GetTypeInfo();
// DelegateCommand allows object or Nullable<>.
// note: Nullable<> is a struct so we cannot use a class constraint.
if (genericTypeInfo.IsValueType)
{
if ((!genericTypeInfo.IsGenericType) || (!typeof(Nullable<>).GetTypeInfo().IsAssignableFrom(genericTypeInfo.GetGenericTypeDefinition().GetTypeInfo())))
{
throw new InvalidCastException("DelegateCommandInvalidGenericPayloadType");
}
}
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
}
///<summary>
///Executes the command and invokes the <see cref="Action{T}"/> provided during construction.
///</summary>
///<param name="parameter">Data used by the command.</param>
public void Execute(T parameter)
{
_executeMethod(parameter);
}
///<summary>
///Determines if the command can execute by invoked the <see cref="Func{T,Bool}"/> provided during construction.
///</summary>
///<param name="parameter">Data used by the command to determine if it can execute.</param>
///<returns>
///<see langword="true" /> if this command can be executed; otherwise, <see langword="false" />.
///</returns>
public bool CanExecute(T parameter)
{
return _canExecuteMethod(parameter);
}
/// <summary>
/// Handle the internal invocation of <see cref="ICommand.Execute(object)"/>
/// </summary>
/// <param name="parameter">Command Parameter</param>
protected override void Execute(object parameter)
{
Execute((T)parameter);
}
/// <summary>
/// Handle the internal invocation of <see cref="ICommand.CanExecute(object)"/>
/// </summary>
/// <param name="parameter"></param>
/// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
protected override bool CanExecute(object parameter)
{
return CanExecute((T)parameter);
}
/// <summary>
/// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
/// </summary>
/// <typeparam name="TType">The type of the return value of the method that this delegate encapulates</typeparam>
/// <param name="propertyExpression">The property expression. Example: ObservesProperty(() => PropertyName).</param>
/// <returns>The current instance of DelegateCommand</returns>
public DelegateCommand<T> ObservesProperty<TType>(Expression<Func<TType>> propertyExpression)
{
ObservesPropertyInternal(propertyExpression);
return this;
}
/// <summary>
/// Observes a property that is used to determine if this command can execute, and if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
/// </summary>
/// <param name="canExecuteExpression">The property expression. Example: ObservesCanExecute(() => PropertyName).</param>
/// <returns>The current instance of DelegateCommand</returns>
public DelegateCommand<T> ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
{
Expression<Func<T, bool>> expression = System.Linq.Expressions.Expression.Lambda<Func<T, bool>>(canExecuteExpression.Body, System.Linq.Expressions.Expression.Parameter(typeof(T), "o"));
_canExecuteMethod = expression.Compile();
ObservesPropertyInternal(canExecuteExpression);
return this;
}
}
}

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Commands
{
/// <summary>
/// An <see cref="ICommand"/> whose delegates do not take any parameters for <see cref="Execute()"/> and <see cref="CanExecute()"/>.
/// </summary>
/// <see cref="DelegateCommandBase"/>
/// <see cref="DelegateCommand{T}"/>
public class DelegateCommand : DelegateCommandBase
{
Action _executeMethod;
Func<bool> _canExecuteMethod;
/// <summary>
/// Creates a new instance of <see cref="DelegateCommand"/> with the <see cref="Action"/> to invoke on execution.
/// </summary>
/// <param name="executeMethod">The <see cref="Action"/> to invoke when <see cref="ICommand.Execute(object)"/> is called.</param>
public DelegateCommand(Action executeMethod)
: this(executeMethod, () => true)
{
}
/// <summary>
/// Creates a new instance of <see cref="DelegateCommand"/> with the <see cref="Action"/> to invoke on execution
/// and a <see langword="Func" /> to query for determining if the command can execute.
/// </summary>
/// <param name="executeMethod">The <see cref="Action"/> to invoke when <see cref="ICommand.Execute"/> is called.</param>
/// <param name="canExecuteMethod">The <see cref="Func{TResult}"/> to invoke when <see cref="ICommand.CanExecute"/> is called</param>
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
: base()
{
if (executeMethod == null || canExecuteMethod == null)
throw new ArgumentNullException(nameof(executeMethod), "DelegateCommandDelegatesCannotBeNull");
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
}
///<summary>
/// Executes the command.
///</summary>
public void Execute()
{
_executeMethod();
}
/// <summary>
/// Determines if the command can be executed.
/// </summary>
/// <returns>Returns <see langword="true"/> if the command can execute,otherwise returns <see langword="false"/>.</returns>
public bool CanExecute()
{
return _canExecuteMethod();
}
/// <summary>
/// Handle the internal invocation of <see cref="ICommand.Execute(object)"/>
/// </summary>
/// <param name="parameter">Command Parameter</param>
protected override void Execute(object parameter)
{
Execute();
}
/// <summary>
/// Handle the internal invocation of <see cref="ICommand.CanExecute(object)"/>
/// </summary>
/// <param name="parameter"></param>
/// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
protected override bool CanExecute(object parameter)
{
return CanExecute();
}
/// <summary>
/// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
/// </summary>
/// <typeparam name="T">The object type containing the property specified in the expression.</typeparam>
/// <param name="propertyExpression">The property expression. Example: ObservesProperty(() => PropertyName).</param>
/// <returns>The current instance of DelegateCommand</returns>
public DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression)
{
ObservesPropertyInternal(propertyExpression);
return this;
}
/// <summary>
/// Observes a property that is used to determine if this command can execute, and if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
/// </summary>
/// <param name="canExecuteExpression">The property expression. Example: ObservesCanExecute(() => PropertyName).</param>
/// <returns>The current instance of DelegateCommand</returns>
public DelegateCommand ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
{
_canExecuteMethod = canExecuteExpression.Compile();
ObservesPropertyInternal(canExecuteExpression);
return this;
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
namespace AIStudio.Wpf.ADiagram.Commands
{
/// <summary>
/// An <see cref="ICommand"/> whose delegates can be attached for <see cref="Execute"/> and <see cref="CanExecute"/>.
/// </summary>
public abstract class DelegateCommandBase : ICommand, IActiveAware
{
private bool _isActive;
private SynchronizationContext _synchronizationContext;
private readonly HashSet<string> _observedPropertiesExpressions = new HashSet<string>();
/// <summary>
/// Creates a new instance of a <see cref="DelegateCommandBase"/>, specifying both the execute action and the can execute function.
/// </summary>
protected DelegateCommandBase()
{
_synchronizationContext = SynchronizationContext.Current;
}
/// <summary>
/// Occurs when changes occur that affect whether or not the command should execute.
/// </summary>
public virtual event EventHandler CanExecuteChanged;
/// <summary>
/// Raises <see cref="ICommand.CanExecuteChanged"/> so every
/// command invoker can requery <see cref="ICommand.CanExecute"/>.
/// </summary>
protected virtual void OnCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
if (_synchronizationContext != null && _synchronizationContext != SynchronizationContext.Current)
_synchronizationContext.Post((o) => handler.Invoke(this, EventArgs.Empty), null);
else
handler.Invoke(this, EventArgs.Empty);
}
}
/// <summary>
/// Raises <see cref="CanExecuteChanged"/> so every command invoker
/// can requery to check if the command can execute.
/// </summary>
/// <remarks>Note that this will trigger the execution of <see cref="CanExecuteChanged"/> once for each invoker.</remarks>
[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
void ICommand.Execute(object parameter)
{
Execute(parameter);
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute(parameter);
}
/// <summary>
/// Handle the internal invocation of <see cref="ICommand.Execute(object)"/>
/// </summary>
/// <param name="parameter">Command Parameter</param>
protected abstract void Execute(object parameter);
/// <summary>
/// Handle the internal invocation of <see cref="ICommand.CanExecute(object)"/>
/// </summary>
/// <param name="parameter"></param>
/// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
protected abstract bool CanExecute(object parameter);
/// <summary>
/// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
/// </summary>
/// <typeparam name="T">The object type containing the property specified in the expression.</typeparam>
/// <param name="propertyExpression">The property expression. Example: ObservesProperty(() => PropertyName).</param>
protected internal void ObservesPropertyInternal<T>(Expression<Func<T>> propertyExpression)
{
if (_observedPropertiesExpressions.Contains(propertyExpression.ToString()))
{
throw new ArgumentException($"{propertyExpression.ToString()} is already being observed.",
nameof(propertyExpression));
}
else
{
_observedPropertiesExpressions.Add(propertyExpression.ToString());
PropertyObserver.Observes(propertyExpression, RaiseCanExecuteChanged);
}
}
#region IsActive
/// <summary>
/// Gets or sets a value indicating whether the object is active.
/// </summary>
/// <value><see langword="true" /> if the object is active; otherwise <see langword="false" />.</value>
public bool IsActive
{
get { return _isActive; }
set
{
if (_isActive != value)
{
_isActive = value;
OnIsActiveChanged();
}
}
}
/// <summary>
/// Fired if the <see cref="IsActive"/> property changes.
/// </summary>
public virtual event EventHandler IsActiveChanged;
/// <summary>
/// This raises the <see cref="DelegateCommandBase.IsActiveChanged"/> event.
/// </summary>
protected virtual void OnIsActiveChanged()
{
IsActiveChanged?.Invoke(this, EventArgs.Empty);
}
#endregion
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Commands
{
/// <summary>
/// Interface that defines if the object instance is active
/// and notifies when the activity changes.
/// </summary>
public interface IActiveAware
{
/// <summary>
/// Gets or sets a value indicating whether the object is active.
/// </summary>
/// <value><see langword="true" /> if the object is active; otherwise <see langword="false" />.</value>
bool IsActive { get; set; }
/// <summary>
/// Notifies that the value for <see cref="IsActive"/> property has changed.
/// </summary>
event EventHandler IsActiveChanged;
}
}

View File

@@ -0,0 +1,68 @@
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 AIStudio.Wpf.ADiagram.Commands
{
/// <summary>
/// Provide a way to observe property changes of INotifyPropertyChanged objects and invokes a
/// custom action when the PropertyChanged event is fired.
/// </summary>
internal class PropertyObserver
{
private readonly Action _action;
private PropertyObserver(System.Linq.Expressions.Expression propertyExpression, Action action)
{
_action = action;
SubscribeListeners(propertyExpression);
}
private void SubscribeListeners(System.Linq.Expressions.Expression propertyExpression)
{
var propNameStack = new Stack<PropertyInfo>();
while (propertyExpression is MemberExpression temp) // Gets the root of the property chain.
{
propertyExpression = temp.Expression;
propNameStack.Push(temp.Member as PropertyInfo); // Records the member info as property info
}
if (!(propertyExpression is ConstantExpression constantExpression))
throw new NotSupportedException("Operation not supported for the given expression type. " +
"Only MemberExpression and ConstantExpression are currently supported.");
var propObserverNodeRoot = new PropertyObserverNode(propNameStack.Pop(), _action);
PropertyObserverNode previousNode = propObserverNodeRoot;
foreach (var propName in propNameStack) // Create a node chain that corresponds to the property chain.
{
var currentNode = new PropertyObserverNode(propName, _action);
previousNode.Next = currentNode;
previousNode = currentNode;
}
object propOwnerObject = constantExpression.Value;
if (!(propOwnerObject is INotifyPropertyChanged inpcObject))
throw new InvalidOperationException("Trying to subscribe PropertyChanged listener in object that " +
$"owns '{propObserverNodeRoot.PropertyInfo.Name}' property, but the object does not implements INotifyPropertyChanged.");
propObserverNodeRoot.SubscribeListenerFor(inpcObject);
}
/// <summary>
/// Observes a property that implements INotifyPropertyChanged, and automatically calls a custom action on
/// property changed notifications. The given expression must be in this form: "() => Prop.NestedProp.PropToObserve".
/// </summary>
/// <param name="propertyExpression">Expression representing property to be observed. Ex.: "() => Prop.NestedProp.PropToObserve".</param>
/// <param name="action">Action to be invoked when PropertyChanged event occours.</param>
internal static PropertyObserver Observes<T>(Expression<Func<T>> propertyExpression, Action action)
{
return new PropertyObserver(propertyExpression.Body, action);
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Commands
{
/// <summary>
/// Represents each node of nested properties expression and takes care of
/// subscribing/unsubscribing INotifyPropertyChanged.PropertyChanged listeners on it.
/// </summary>
internal class PropertyObserverNode
{
private readonly Action _action;
private INotifyPropertyChanged _inpcObject;
public PropertyInfo PropertyInfo { get; }
public PropertyObserverNode Next { get; set; }
public PropertyObserverNode(PropertyInfo propertyInfo, Action action)
{
PropertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo));
_action = () =>
{
action?.Invoke();
if (Next == null) return;
Next.UnsubscribeListener();
GenerateNextNode();
};
}
public void SubscribeListenerFor(INotifyPropertyChanged inpcObject)
{
_inpcObject = inpcObject;
_inpcObject.PropertyChanged += OnPropertyChanged;
if (Next != null) GenerateNextNode();
}
private void GenerateNextNode()
{
var nextProperty = PropertyInfo.GetValue(_inpcObject);
if (nextProperty == null) return;
if (!(nextProperty is INotifyPropertyChanged nextInpcObject))
throw new InvalidOperationException("Trying to subscribe PropertyChanged listener in object that " +
$"owns '{Next.PropertyInfo.Name}' property, but the object does not implements INotifyPropertyChanged.");
Next.SubscribeListenerFor(nextInpcObject);
}
private void UnsubscribeListener()
{
if (_inpcObject != null)
_inpcObject.PropertyChanged -= OnPropertyChanged;
Next?.UnsubscribeListener();
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e?.PropertyName == PropertyInfo.Name || string.IsNullOrEmpty(e?.PropertyName))
{
_action?.Invoke();
}
}
}
}

View File

@@ -0,0 +1,98 @@
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.Media;
using System.Windows.Media.Animation;
namespace AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// 包含一些常用的动画辅助方法
/// </summary>
public class AnimationHelper
{
/// <summary>
/// 创建一个Thickness动画
/// </summary>
/// <param name="thickness"></param>
/// <param name="milliseconds"></param>
/// <returns></returns>
public static ThicknessAnimation CreateAnimation(Thickness thickness = default, double milliseconds = 200)
{
return new ThicknessAnimation(thickness, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
{
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
};
}
/// <summary>
/// 创建一个Double动画
/// </summary>
/// <param name="toValue"></param>
/// <param name="milliseconds"></param>
/// <returns></returns>
public static DoubleAnimation CreateAnimation(double toValue, double milliseconds = 200)
{
return new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
{
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
};
}
public const string DigitsPattern = @"[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?";
internal static void DecomposeGeometryStr(string geometryStr, out double[] arr)
{
var collection = Regex.Matches(geometryStr, DigitsPattern);
arr = new double[collection.Count];
for (var i = 0; i < collection.Count; i++)
{
arr[i] = Convert.ToDouble(collection[i].Value);
}
}
internal static Geometry ComposeGeometry(string[] strings, double[] arr)
{
var builder = new StringBuilder(strings[0]);
for (var i = 0; i < arr.Length; i++)
{
var s = strings[i + 1];
var n = arr[i];
if (!double.IsNaN(n))
{
builder.Append(n).Append(s);
}
}
return Geometry.Parse(builder.ToString());
}
internal static Geometry InterpolateGeometry(double[] from, double[] to, double progress, string[] strings)
{
var accumulated = new double[to.Length];
for (var i = 0; i < to.Length; i++)
{
var fromValue = from[i];
accumulated[i] = fromValue + (to[i] - fromValue) * progress;
}
return ComposeGeometry(strings, accumulated);
}
internal static double[] InterpolateGeometryValue(double[] from, double[] to, double progress)
{
var accumulated = new double[to.Length];
for (var i = 0; i < to.Length; i++)
{
var fromValue = from[i];
accumulated[i] = fromValue + (to[i] - fromValue) * progress;
}
return accumulated;
}
}
}

View File

@@ -0,0 +1,23 @@
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.Barcode"
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:AIStudio.Wpf.ADiagram.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Path Name="imageBarcodeEncoderGeometry" Grid.RowSpan="3" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Black" Stretch="Fill" Width="Auto" Height="Auto" />
<ContentControl x:Name="PART_Icon" Grid.Row="1" Grid.Column="1"/>
</Grid>
</UserControl>

View File

@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.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 WpfAnimatedGif;
using ZXing;
using ZXing.Presentation;
namespace AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// Barcode.xaml 的交互逻辑
/// </summary>
public partial class Barcode : UserControl
{
public Barcode()
{
InitializeComponent();
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof(string), typeof(Barcode), new FrameworkPropertyMetadata(
string.Empty,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated));
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly DependencyProperty FormatProperty = DependencyProperty.Register(
"Format", typeof(BarcodeFormat), typeof(Barcode), new FrameworkPropertyMetadata(
BarcodeFormat.QR_CODE,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated));
public BarcodeFormat Format
{
get => (BarcodeFormat)GetValue(FormatProperty);
set => SetValue(FormatProperty, value);
}
public static readonly DependencyProperty SizeProperty = DependencyProperty.Register(
"Size", typeof(double), typeof(Barcode), new FrameworkPropertyMetadata(
512d,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated));
public double Size
{
get => (double)GetValue(SizeProperty);
set => SetValue(SizeProperty, value);
}
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
"Icon", typeof(string), typeof(Barcode), new FrameworkPropertyMetadata(null, OnIconChanged));
public string Icon
{
get => (string)GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var barcode = (Barcode)d;
barcode.OnIconChanged();
}
private void OnIconChanged()
{
if (!string.IsNullOrEmpty(this.Icon))
{
var suffix = System.IO.Path.GetExtension(this.Icon).ToLower();
Image image = new Image() { Stretch = Stretch.UniformToFill };
var icon = new BitmapImage(new Uri(Icon));
if (suffix != ".gif")
{
image.Source = icon;
}
else
{
image.SetCurrentValue(ImageBehavior.AnimatedSourceProperty, icon);
image.SetCurrentValue(ImageBehavior.AutoStartProperty, true);
}
PART_Icon.Content = image;
}
else
{
PART_Icon.Content = null;
}
}
private static void OnFormattedTextInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var barcode = (Barcode)d;
barcode.OnFormattedTextInvalidated();
}
private void OnFormattedTextInvalidated()
{
var writer = new BarcodeWriterGeometry
{
Format = Format,
Options = new ZXing.Common.EncodingOptions
{
Height = (int)this.Size,
Width = (int)this.Size,
Margin = 0
}
};
var image = writer.Write(Text ?? "AIStudio画板");
imageBarcodeEncoderGeometry.Data = image;
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace AIStudio.Wpf.ADiagram.Controls
{
public class CancelRoutedEventArgs : RoutedEventArgs
{
public CancelRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
{
}
public bool Cancel { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// 带上下文菜单的切换按钮
/// </summary>
public class ContextMenuToggleButton : ToggleButton
{
public ContextMenu Menu { get; set; }
protected override void OnClick()
{
base.OnClick();
if (Menu != null)
{
if (IsChecked == true)
{
Menu.PlacementTarget = this;
Menu.IsOpen = true;
}
else
{
Menu.IsOpen = false;
}
}
}
}
}

View File

@@ -0,0 +1,139 @@
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.GradientStopControl"
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:AIStudio.Wpf.ADiagram.Controls"
xmlns:Fluent="urn:fluent-ribbon"
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
xmlns:helper="clr-namespace:AIStudio.Wpf.ADiagram.Helpers"
xmlns:dd="https://astudio.github.io/diagram"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ControlTemplate x:Key="RibbonDropDownButtonControlTemplate1" TargetType="{x:Type Fluent:DropDownButton}">
<Grid>
<Border x:Name="PART_ButtonBorder" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Height="Auto">
<StackPanel x:Name="stackPanel" Margin="{TemplateBinding Padding}" Width="Auto" Orientation="Vertical">
<ContentPresenter x:Name="iconImage" Content="{Binding Icon, RelativeSource={RelativeSource TemplatedParent}}" Width="Auto" SnapsToDevicePixels="True" />
</StackPanel>
</Border>
<Popup x:Name="PART_Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Margin="0,0,-4,0" VerticalAlignment="Top" Grid.ColumnSpan="2">
<Grid Name="DropDown" SnapsToDevicePixels="True" Margin="0" VerticalAlignment="Top">
<Border x:Name="PART_DropDownBorder" MinWidth="{TemplateBinding ActualWidth}" SnapsToDevicePixels="True" Background="{DynamicResource Fluent.Ribbon.Brushes.DropDown.BackgroundBrush}" BorderBrush="{DynamicResource Fluent.Ribbon.Brushes.DropDown.BorderBrush}" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Grid Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Border VerticalAlignment="Top" Width="Auto" Height="Auto" BorderBrush="{DynamicResource Fluent.Ribbon.Brushes.DropDown.BackgroundBrush}" BorderThickness="1" />
<Grid Margin="1" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer x:Name="PART_ScrollViewer" Style="{DynamicResource MenuScrollViewer}" IsTabStop="False" Margin="1" MaxHeight="{TemplateBinding MaxDropDownHeight}" SnapsToDevicePixels="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden">
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Local" />
</ScrollViewer>
<Border x:Name="resizeBorder" HorizontalAlignment="Stretch" VerticalAlignment="Top" Height="11" BorderBrush="{DynamicResource Fluent.Ribbon.Brushes.DropDown.Resize.BorderBrush}" BorderThickness="0,1,0,0" Grid.Row="1" Background="{DynamicResource Fluent.Ribbon.Brushes.DropDown.Resize.BackgroundBrush}">
<Grid>
<Thumb x:Name="PART_ResizeVerticalThumb" HorizontalAlignment="Stretch" Margin="0,0,0,-90" Width="Auto" Height="10" VerticalAlignment="Top" Cursor="SizeNS" Template="{DynamicResource ResizeVerticalThumbControlTemplate}" />
<Thumb x:Name="PART_ResizeBothThumb" HorizontalAlignment="Right" Margin="0,0,0,-90" Width="10" Height="10" VerticalAlignment="Top" Cursor="SizeNWSE" Template="{DynamicResource ResizeBothThumbControlTemplate}" />
</Grid>
</Border>
</Grid>
</Grid>
</Border>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ResizeMode" Value="None">
<Setter Property="Visibility" TargetName="resizeBorder" Value="Collapsed" />
</Trigger>
<Trigger Property="ResizeMode" Value="Both">
<Setter Property="Visibility" TargetName="PART_ResizeVerticalThumb" Value="Collapsed" />
<Setter Property="Visibility" TargetName="PART_ResizeBothThumb" Value="Visible" />
<Setter Property="Visibility" TargetName="resizeBorder" Value="Visible" />
</Trigger>
<Trigger Property="ResizeMode" Value="Vertical">
<Setter Property="Visibility" TargetName="PART_ResizeBothThumb" Value="Collapsed" />
<Setter Property="Visibility" TargetName="PART_ResizeVerticalThumb" Value="Visible" />
<Setter Property="Visibility" TargetName="resizeBorder" Value="Visible" />
</Trigger>
<Trigger Property="IsDropDownOpen" Value="True">
<Setter Property="BorderBrush" TargetName="PART_ButtonBorder" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.Pressed.BorderBrush}" />
<Setter Property="Background" TargetName="PART_ButtonBorder" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.Pressed.Background}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="iconImage" Value="0.5" />
<Setter Property="Effect" TargetName="iconImage">
<Setter.Value>
<Fluent:GrayscaleEffect />
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="IsDropDownOpen" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="PART_ButtonBorder" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.MouseOver.Background}" />
<Setter Property="BorderBrush" TargetName="PART_ButtonBorder" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.MouseOver.BorderBrush}" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Resources>
<StackPanel>
<DockPanel>
<Fluent:Button DockPanel.Dock="Right" Size="Small"
Icon="{iconPacks:Material Kind=Minus}" Command="{Binding DeleteGradientStopCommand}" Margin="5" />
<Fluent:Button DockPanel.Dock="Right" Size="Small"
Icon="{iconPacks:Material Kind=Plus}" Command="{Binding AddGradientStopCommand}" Margin="5" />
<TextBlock Text="渐变光圈" VerticalAlignment="Center" Margin="5"/>
</DockPanel>
<Grid Margin="5">
<Rectangle Fill="{Binding GradientStop, Converter={StaticResource ColorBrushConverter}}" Height="4.0" VerticalAlignment="Center" />
<ItemsControl ItemsSource="{Binding GradientStop}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid >
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Slider Maximum="1" Minimum="0" LargeChange="0.1" SmallChange="0.01"
Value="{Binding Offset}"
Foreground="{Binding Color, Converter={StaticResource ColorBrushConverter}}"
Style="{StaticResource TransparentSlider}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<DockPanel>
<!-- The following code shows theme colors mode for color gallery -->
<Fluent:DropDownButton DockPanel.Dock="Right" Margin="5" Height="24" Width="60"
Template="{StaticResource RibbonDropDownButtonControlTemplate1}"
MaxDropDownHeight="500">
<Fluent:DropDownButton.Icon>
<Grid>
<Rectangle Height="22" StrokeThickness="1" Stroke="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding SelectedGradientStop.Color}" />
</Rectangle.Fill>
</Rectangle>
</Grid>
</Fluent:DropDownButton.Icon>
<Fluent:ColorGallery SelectedColor="{Binding SelectedGradientStop.Color, Mode=TwoWay}"
Mode="StandardColors"
StandardColorGridRows="3"
Columns="10"
ThemeColorGridRows="5"
IsNoColorButtonVisible="True" />
</Fluent:DropDownButton>
<TextBlock Margin="5" VerticalAlignment="Center" Text="颜色"/>
</DockPanel>
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,46 @@
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 Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// GradientStopControl.xaml 的交互逻辑
/// </summary>
public partial class GradientStopControl : UserControl
{
public GradientStopControl()
{
InitializeComponent();
}
public ColorObject ColorObject
{
get { return this.DataContext as ColorObject; }
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseDown(e);
var element = (e.OriginalSource as FrameworkElement);
if (element.DataContext is Util.DiagramDesigner.GradientStop target)
{
ColorObject.SelectedGradientStop = target;
}
}
}
}

View File

@@ -0,0 +1,99 @@
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.MultiSelectComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ComboBox Background="Transparent" BorderBrush="Transparent"
x:Name="MultiSelectCombo"
SnapsToDevicePixels="True"
OverridesDefaultStyle="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True"
IsSynchronizedWithCurrentItem="True"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Title}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"
Tag="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"
Click="CheckBox_Click" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.Template>
<ControlTemplate TargetType="ComboBox">
<Grid >
<ToggleButton x:Name="ToggleButton" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
Grid.Column="2" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
Focusable="false"
ClickMode="Press" HorizontalContentAlignment="Left" >
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12"/>
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.ColumnSpan="2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" />
<Border
x:Name="BorderComp"
Grid.Column="0"
CornerRadius="2"
Margin="1"
BorderThickness="0,0,0,0" >
<TextBlock Text="{Binding Path=Text,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" Padding="3" />
</Border>
<Border x:Name="ArrowBorder" Grid.Column="1" >
<Path
x:Name="Arrow"
Stretch="Fill" Width="5" Height="3"
Fill="Black"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="ArrowBorder" Property="Background" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.MouseOver.Background}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<Popup x:Name="Popup"
Placement="Bottom"
AllowsTransparency="True"
Focusable="False" IsOpen="{TemplateBinding IsDropDownOpen}"
PopupAnimation="Slide">
<Grid x:Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder"
BorderThickness="1" Background="{DynamicResource WhiteBrush}"
BorderBrush="{DynamicResource GrayBrush8}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True" DataContext="{Binding}">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<Trigger Property="IsDropDownOpen" Value="true">
<Setter TargetName="ToggleButton" Property="Background" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.MouseOver.Background}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ComboBox.Template>
</ComboBox>
</UserControl>

View File

@@ -0,0 +1,334 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Collections;
using AIStudio.Wpf.ADiagram.Helpers;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// Interaction logic for MultiSelectComboBox.xaml
/// </summary>
public partial class MultiSelectComboBox : UserControl
{
private ObservableCollection<Node> _nodeList;
public MultiSelectComboBox()
{
InitializeComponent();
_nodeList = new ObservableCollection<Node>();
}
#region Dependency Properties
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IList), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnItemsSourceChanged)));
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnSelectedItemsChanged)));
public static readonly DependencyProperty SelectedValuesProperty =
DependencyProperty.Register("SelectedValues", typeof(IList), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnSelectedValuesChanged)));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));
public static readonly DependencyProperty DefaultTextProperty =
DependencyProperty.Register("DefaultText", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));
public string DisplayMemberPath { get; set; }
public string SelectedValuePath { get; set; }
public IList ItemsSource
{
get { return (IList)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
}
}
public IList SelectedItems
{
get { return (IList)GetValue(SelectedItemsProperty); }
set
{
SetValue(SelectedItemsProperty, value);
}
}
public IList SelectedValues
{
get { return (IList)GetValue(SelectedValuesProperty); }
set
{
SetValue(SelectedValuesProperty, value);
}
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public string DefaultText
{
get { return (string)GetValue(DefaultTextProperty); }
set { SetValue(DefaultTextProperty, value); }
}
#endregion
#region Events
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.DisplayInControl();
}
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.SelectNodes();
control.SetText();
}
private static void OnSelectedValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.SelectNodes();
control.SetText();
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox clickedBox = (CheckBox)sender;
if (clickedBox.Content.ToString() == "All")
{
if (clickedBox.IsChecked.Value)
{
foreach (Node node in _nodeList)
{
node.IsSelected = true;
}
}
else
{
foreach (Node node in _nodeList)
{
node.IsSelected = false;
}
}
}
else
{
int _selectedCount = 0;
foreach (Node s in _nodeList)
{
if (s.IsSelected && s.Object.ToString() != "All")
_selectedCount++;
}
if (_selectedCount == _nodeList.Count - 1)
_nodeList.FirstOrDefault(i => i.Object.ToString() == "All").IsSelected = true;
else
_nodeList.FirstOrDefault(i => i.Object.ToString() == "All").IsSelected = false;
}
SetSelectedItems();
SetText();
}
#endregion
#region Methods
private void SelectNodes()
{
if (SelectedItems != null)
{
foreach (var item in SelectedItems)
{
Node node = _nodeList.FirstOrDefault(i => i.Object == item);
if (node != null)
node.IsSelected = true;
}
}
else if (SelectedValues != null)
{
foreach (var item in SelectedValues)
{
Node node = _nodeList.FirstOrDefault(i => i.Object != null && i.Object.ToString() != "All" && i.Object.GetPropertyValue(SelectedValuePath) == item);
if (node != null)
node.IsSelected = true;
}
}
}
private void SetSelectedItems()
{
if (SelectedItems != null)
{
SelectedItems.Clear();
foreach (Node node in _nodeList)
{
if (node.IsSelected && node.Object.ToString() != "All")
{
if (this.ItemsSource.Count > 0)
{
if (SelectedItems != null)
{
SelectedItems.Add(node.Object);
}
}
}
}
}
if (SelectedValues != null)
{
SelectedValues.Clear();
foreach (Node node in _nodeList)
{
if (node.IsSelected && node.Object.ToString() != "All")
{
if (this.ItemsSource.Count > 0)
{
if (SelectedValues != null)
{
SelectedValues.Add(node.Object.GetPropertyValue(SelectedValuePath));
}
}
}
}
}
}
private void DisplayInControl()
{
_nodeList.Clear();
if (this.ItemsSource.Count > 0)
_nodeList.Add(new Node("All", DisplayMemberPath));
foreach (var item in this.ItemsSource)
{
Node node = new Node(item, DisplayMemberPath);
_nodeList.Add(node);
}
MultiSelectCombo.ItemsSource = _nodeList;
}
private void SetText()
{
StringBuilder displayText = new StringBuilder();
foreach (Node s in _nodeList)
{
if (s.IsSelected == true && s.Object.ToString() == "All")
{
displayText = new StringBuilder();
displayText.Append("All");
break;
}
else if (s.IsSelected == true && s.Object.ToString() != "All")
{
displayText.Append(s.Object);
displayText.Append(',');
}
}
this.Text = displayText.ToString().TrimEnd(new char[] { ',' });
// set DefaultText if nothing else selected
if (string.IsNullOrEmpty(this.Text))
{
this.Text = this.DefaultText;
}
}
#endregion
}
public class Node : INotifyPropertyChanged
{
#region ctor
public Node(object obj, string displayMemberPath)
{
Object = obj;
if (!string.IsNullOrEmpty(displayMemberPath) && Object.ContainsProperty(displayMemberPath))
Title = Object.GetPropertyValue(displayMemberPath).ToString();
else
Title = obj.ToString();
}
#endregion
#region Properties
private object _object;
public object Object
{
get
{
return _object;
}
set
{
_object = value;
NotifyPropertyChanged("Object");
}
}
private string _title;
public string Title
{
get
{
return _title;
}
set
{
_title = value;
NotifyPropertyChanged("Title");
}
}
private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

View File

@@ -0,0 +1,310 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
namespace AIStudio.Wpf.ADiagram.Controls
{
public class OutlineText : FrameworkElement
{
private Pen _pen;
private FormattedText _formattedText;
private Geometry _textGeometry;
private PathGeometry _clipGeometry;
static OutlineText()
{
SnapsToDevicePixelsProperty.OverrideMetadata(typeof(OutlineText), new FrameworkPropertyMetadata(true));
UseLayoutRoundingProperty.OverrideMetadata(typeof(OutlineText), new FrameworkPropertyMetadata(true));
}
public static readonly DependencyProperty StrokePositionProperty = DependencyProperty.Register(
"StrokePosition", typeof(StrokePosition), typeof(OutlineText), new PropertyMetadata(default(StrokePosition)));
public StrokePosition StrokePosition
{
get => (StrokePosition)GetValue(StrokePositionProperty);
set => SetValue(StrokePositionProperty, value);
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof(string), typeof(OutlineText), new FrameworkPropertyMetadata(
string.Empty,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated));
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register(
"TextAlignment", typeof(TextAlignment), typeof(OutlineText),
new PropertyMetadata(default(TextAlignment), OnFormattedTextUpdated));
public TextAlignment TextAlignment
{
get => (TextAlignment)GetValue(TextAlignmentProperty);
set => SetValue(TextAlignmentProperty, value);
}
public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register(
"TextTrimming", typeof(TextTrimming), typeof(OutlineText),
new PropertyMetadata(default(TextTrimming), OnFormattedTextInvalidated));
public TextTrimming TextTrimming
{
get => (TextTrimming)GetValue(TextTrimmingProperty);
set => SetValue(TextTrimmingProperty, value);
}
public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register(
"TextWrapping", typeof(TextWrapping), typeof(OutlineText),
new PropertyMetadata(TextWrapping.NoWrap, OnFormattedTextInvalidated));
public TextWrapping TextWrapping
{
get => (TextWrapping)GetValue(TextWrappingProperty);
set => SetValue(TextWrappingProperty, value);
}
public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
"Fill", typeof(Brush), typeof(OutlineText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated));
public Brush Fill
{
get => (Brush)GetValue(FillProperty);
set => SetValue(FillProperty, value);
}
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
"Stroke", typeof(Brush), typeof(OutlineText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated));
public Brush Stroke
{
get => (Brush)GetValue(StrokeProperty);
set => SetValue(StrokeProperty, value);
}
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
"StrokeThickness", typeof(double), typeof(OutlineText), new PropertyMetadata(0d, OnFormattedTextUpdated));
public double StrokeThickness
{
get => (double)GetValue(StrokeThicknessProperty);
set => SetValue(StrokeThicknessProperty, value);
}
public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(
typeof(OutlineText),
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
public FontFamily FontFamily
{
get => (FontFamily)GetValue(FontFamilyProperty);
set => SetValue(FontFamilyProperty, value);
}
public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner(
typeof(OutlineText),
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
[TypeConverter(typeof(FontSizeConverter))]
public double FontSize
{
get => (double)GetValue(FontSizeProperty);
set => SetValue(FontSizeProperty, value);
}
public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(
typeof(OutlineText),
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
public FontStretch FontStretch
{
get => (FontStretch)GetValue(FontStretchProperty);
set => SetValue(FontStretchProperty, value);
}
public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(
typeof(OutlineText),
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
public FontStyle FontStyle
{
get => (FontStyle)GetValue(FontStyleProperty);
set => SetValue(FontStyleProperty, value);
}
public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(
typeof(OutlineText),
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
public FontWeight FontWeight
{
get => (FontWeight)GetValue(FontWeightProperty);
set => SetValue(FontWeightProperty, value);
}
public static readonly DependencyProperty TextDecorationsProperty = DependencyProperty.Register(
"TextDecorations", typeof(TextDecorationCollection), typeof(OutlineText), new PropertyMetadata(null, OnFormattedTextUpdated));
public TextDecorationCollection TextDecorations
{
get => (TextDecorationCollection)GetValue(TextDecorationsProperty);
set => SetValue(TextDecorationsProperty, value);
}
protected override void OnRender(DrawingContext drawingContext)
{
EnsureGeometry();
drawingContext.DrawGeometry(Fill, null, _textGeometry);
if (StrokePosition == StrokePosition.Outside)
{
drawingContext.PushClip(_clipGeometry);
}
else if (StrokePosition == StrokePosition.Inside)
{
drawingContext.PushClip(_textGeometry);
}
drawingContext.DrawGeometry(null, _pen, _textGeometry);
if (StrokePosition == StrokePosition.Outside || StrokePosition == StrokePosition.Inside)
{
drawingContext.Pop();
}
}
private void UpdatePen()
{
_pen = new Pen(Stroke, StrokeThickness);
//if (StrokePosition == StrokePosition.Outside || StrokePosition == StrokePosition.Inside)
//{
// _pen.Thickness = StrokeThickness * 2;
//}
}
private void EnsureFormattedText()
{
if (_formattedText != null || Text == null)
{
return;
}
#if true
_formattedText = new FormattedText(
Text,
CultureInfo.CurrentUICulture,
FlowDirection,
new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
FontSize, Fill);
#else
var source = PresentationSource.FromVisual(this);
var dpi = 1.0;
if (source?.CompositionTarget != null)
{
dpi = 96.0 * source.CompositionTarget.TransformToDevice.M11 / 96.0;
}
_formattedText = new FormattedText(
Text,
CultureInfo.CurrentUICulture,
FlowDirection,
new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
FontSize, Fill, dpi);
#endif
UpdateFormattedText();
}
private void EnsureGeometry()
{
if (_textGeometry != null)
{
return;
}
EnsureFormattedText();
_textGeometry = _formattedText.BuildGeometry(new Point(0, 0));
if (StrokePosition == StrokePosition.Outside)
{
var geometry = new RectangleGeometry(new Rect(0, 0, ActualWidth, ActualHeight));
_clipGeometry = Geometry.Combine(geometry, _textGeometry, GeometryCombineMode.Exclude, null);
}
}
private void UpdateFormattedText()
{
if (_formattedText == null)
{
return;
}
_formattedText.MaxLineCount = TextWrapping == TextWrapping.NoWrap ? 1 : int.MaxValue;
_formattedText.TextAlignment = TextAlignment;
_formattedText.Trimming = TextTrimming;
_formattedText.SetFontSize(FontSize);
_formattedText.SetFontStyle(FontStyle);
_formattedText.SetFontWeight(FontWeight);
_formattedText.SetFontFamily(FontFamily);
_formattedText.SetFontStretch(FontStretch);
_formattedText.SetTextDecorations(TextDecorations);
}
private static void OnFormattedTextUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var outlinedTextBlock = (OutlineText)d;
outlinedTextBlock.UpdateFormattedText();
outlinedTextBlock._textGeometry = null;
outlinedTextBlock.InvalidateMeasure();
outlinedTextBlock.InvalidateVisual();
}
private static void OnFormattedTextInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var outlinedTextBlock = (OutlineText)d;
outlinedTextBlock._formattedText = null;
outlinedTextBlock._textGeometry = null;
outlinedTextBlock.InvalidateMeasure();
outlinedTextBlock.InvalidateVisual();
}
protected override Size MeasureOverride(Size availableSize)
{
EnsureFormattedText();
// constrain the formatted text according to the available size
// the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions
// the Math.Max call is to ensure we don't hit zero, which will cause MaxTextHeight to throw
_formattedText.MaxTextWidth = Math.Min(3579139, availableSize.Width);
_formattedText.MaxTextHeight = Math.Max(0.0001d, availableSize.Height);
UpdatePen();
// return the desired size
return new Size(_formattedText.Width, _formattedText.Height);
}
}
public enum StrokePosition
{
Center,
Outside,
Inside
}
}

View File

@@ -0,0 +1,34 @@
<Window x:Class="AIStudio.Wpf.ADiagram.Controls.PopupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{Binding Title}"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner"
x:Name="theView">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Content="{Binding ElementName=theView, Path=DataContext}" />
<StackPanel Grid.Row="1"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="Ok"
IsDefault="True"
Click="Ok_Click"
Margin="5"
Width="100"
Height="30" />
<Button Content="Cancel"
IsCancel="True"
Margin="5"
Width="100"
Height="30" />
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,33 @@
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 AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// PopupWindow.xaml 的交互逻辑
/// </summary>
public partial class PopupWindow : Window
{
public PopupWindow()
{
InitializeComponent();
}
private void Ok_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
this.Close();
}
}
}

View File

@@ -0,0 +1,63 @@
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.PropertiesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Border x:Name="border" BorderThickness="1" BorderBrush="{DynamicResource GrayBrush8}">
<Border.Resources>
<ControlTemplate x:Key="validationErrorTemplate">
<DockPanel>
<Image Source="/AIStudio.Wpf.ADiagram;component/Images/error.png" Height="16" Width="16"
DockPanel.Dock="Right" Margin="-18,0,0,0"
ToolTip="{Binding ElementName=adorner,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
</Image>
<AdornedElementPlaceholder x:Name="adorner"/>
</DockPanel>
</ControlTemplate>
<Style x:Key="gridLineStyle" TargetType="Line">
<Setter Property="Stroke" Value="{DynamicResource GrayBrush8}" />
<Setter Property="Stretch" Value="Fill" />
<Setter Property="Grid.ZIndex" Value="1000" />
</Style>
<Style x:Key="gridHorizontalLineStyle" TargetType="Line" BasedOn="{StaticResource gridLineStyle}">
<Setter Property="X2" Value="1" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Grid.ColumnSpan"
Value="{Binding
Path=ColumnDefinitions.Count,
RelativeSource={RelativeSource AncestorType=Grid}}"/>
</Style>
<Style x:Key="gridVerticalLineStyle" TargetType="Line" BasedOn="{StaticResource gridLineStyle}">
<Setter Property="Y2" Value="1" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Grid.RowSpan"
Value="{Binding
Path=RowDefinitions.Count,
RelativeSource={RelativeSource AncestorType=Grid}}"/>
</Style>
</Border.Resources>
<DockPanel x:Name="_panel">
<Border x:Name="_label" Width="50" Height="16">
<TextBlock Text="Empty" TextAlignment="Center" Foreground="Gray"/>
</Border>
<ScrollViewer x:Name="_gridContainer" VerticalScrollBarVisibility="Auto">
<Grid x:Name="_grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Line Name="_vLine" Grid.Column="0" Grid.RowSpan="1000" Style="{StaticResource gridVerticalLineStyle}"/>
<GridSplitter Name="_splitter" Grid.RowSpan="1000" Margin="0,0,0,0" Width="1"
Background="{DynamicResource GrayBrush8}" Grid.ZIndex="10000"/>
</Grid>
</ScrollViewer>
</DockPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,228 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Reflection;
namespace AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// Interaction logic for PropertiesView.xaml
/// </summary>
public partial class PropertiesView : UserControl
{
#region SelectedObject
public static readonly DependencyProperty SelectedObjectProperty = DependencyProperty.Register("SelectedObject", typeof(object), typeof(PropertiesView), new UIPropertyMetadata(null, OnSelectedObjectChanged));
public object SelectedObject
{
get
{
return (object)GetValue(SelectedObjectProperty);
}
set
{
SetValue(SelectedObjectProperty, value);
}
}
private static void OnSelectedObjectChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
PropertiesView propertyInspector = o as PropertiesView;
if (propertyInspector != null)
propertyInspector.OnSelectedObjectChanged((object)e.OldValue, (object)e.NewValue);
}
protected virtual void OnSelectedObjectChanged(object oldValue, object newValue)
{
// We do not want to process the change now if the grid is initializing (ie. BeginInit/EndInit).
var obj = oldValue as INotifyPropertyChanged;
if (obj != null)
obj.PropertyChanged -= PropertyChanged;
DisplayProperties();
obj = newValue as INotifyPropertyChanged;
if (obj != null)
obj.PropertyChanged += PropertyChanged;
}
#endregion //SelectedObject
public static readonly DependencyProperty NeedBrowsableProperty = DependencyProperty.Register("NeedBrowsable", typeof(bool), typeof(PropertiesView), new UIPropertyMetadata(true));
public bool NeedBrowsable
{
get
{
return (bool)GetValue(NeedBrowsableProperty);
}
set
{
SetValue(NeedBrowsableProperty, value);
}
}
public PropertiesView()
{
InitializeComponent();
this.Loaded += PropertiesView_Loaded;
}
private void PropertiesView_Loaded(object sender, RoutedEventArgs e)
{
DisplayProperties();
}
void PropertyChanged(object sender, PropertyChangedEventArgs e)
{
DisplayProperties();
}
private void DisplayProperties()
{
_panel.Children.Clear();
ClearGrid();
if (SelectedObject != null)
{
int row = 0;
foreach (var prop in SelectedObject.GetType().GetProperties())
{
var attr = prop.GetCustomAttributes(typeof(BrowsableAttribute), true);
if (NeedBrowsable == false && (attr.Length == 0 || (attr[0] as BrowsableAttribute).Browsable))
{
DisplayProperty(prop, row);
row++;
}
else if(NeedBrowsable == true && (attr.Length > 0 && (attr[0] as BrowsableAttribute).Browsable))
{
DisplayProperty(prop, row);
row++;
}
}
_panel.Children.Add(_gridContainer);
}
else
{
_panel.Children.Add(_label);
}
}
private void ClearGrid()
{
_grid.RowDefinitions.Clear();
for (int i = _grid.Children.Count - 1; i >= 0; i--)
{
if (_grid.Children[i] != _vLine && _grid.Children[i] != _splitter)
_grid.Children.RemoveAt(i);
}
}
private void DisplayProperty(PropertyInfo prop, int row)
{
var rowDef = new RowDefinition();
rowDef.Height = new GridLength(Math.Max(20, this.FontSize * 2));
_grid.RowDefinitions.Add(rowDef);
var tb = new TextBlock() { Text = prop.Name };
var displayAttr = prop.GetCustomAttributes(typeof(DisplayNameAttribute), true);
if (displayAttr.Length > 0 )
{
tb.Text = (displayAttr[0] as DisplayNameAttribute).DisplayName;
}
tb.Margin = new Thickness(4);
tb.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(tb, 0);
Grid.SetRow(tb, _grid.RowDefinitions.Count - 1);
_grid.Children.Add(tb);
var line = new Line();
line.Style = (Style)border.Resources["gridHorizontalLineStyle"];
Grid.SetRow(line, row);
_grid.Children.Add(line);
Style style = null;
var styleNameAttr = prop.GetCustomAttributes(typeof(StyleNameAttribute), true);
if (styleNameAttr.Length > 0)
{
style = this.FindResource((styleNameAttr[0] as StyleNameAttribute).Name) as Style;
if (style != null)
{
ContentControl content = new ContentControl();
content.Style = style;
content.DataContext = SelectedObject;
Grid.SetColumn(content, 1);
Grid.SetRow(content, _grid.RowDefinitions.Count - 1);
_grid.Children.Add(content);
}
}
if (style == null)
{
var ed = new TextBox();
ed.PreviewKeyDown += new KeyEventHandler(ed_KeyDown);
ed.Margin = new Thickness(0);
ed.VerticalAlignment = VerticalAlignment.Center;
ed.BorderThickness = new Thickness(0);
Grid.SetColumn(ed, 1);
Grid.SetRow(ed, _grid.RowDefinitions.Count - 1);
var binding = new Binding(prop.Name);
binding.Source = SelectedObject;
binding.ValidatesOnExceptions = true;
binding.Mode = BindingMode.OneWay;
if (prop.CanWrite)
{
var mi = prop.GetSetMethod();
if (mi != null && mi.IsPublic)
binding.Mode = BindingMode.TwoWay;
}
ed.SetBinding(TextBox.TextProperty, binding);
var template = (ControlTemplate)border.Resources["validationErrorTemplate"];
Validation.SetErrorTemplate(ed, template);
_grid.Children.Add(ed);
}
}
void ed_KeyDown(object sender, KeyEventArgs e)
{
var ed = sender as TextBox;
if (ed != null)
{
if (e.Key == Key.Enter)
{
ed.GetBindingExpression(TextBox.TextProperty).UpdateSource();
e.Handled = true;
}
else if (e.Key == Key.Escape)
ed.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
}
}
}
[AttributeUsage(AttributeTargets.Property)]
public class StyleNameAttribute : Attribute
{
private string _name;
public StyleNameAttribute(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}
}

View File

@@ -0,0 +1,349 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace AIStudio.Wpf.ADiagram.Controls
{
public class RectangleGridEventArgs
{
public int Row { get; set; }
public int Column { get; set; }
public RectangleGridEventArgs(int row, int column)
{
Row = row;
Column = column;
}
}
public class RectangleGrid : Grid
{
public static readonly DependencyProperty RowNumProperty = DependencyProperty.Register("RowNum", typeof(int),
typeof(RectangleGrid),
new FrameworkPropertyMetadata(4));
public int RowNum
{
get
{
return (int)GetValue(RowNumProperty);
}
set
{
SetValue(RowNumProperty, value);
}
}
public static readonly DependencyProperty ColumnNumProperty = DependencyProperty.Register("ColumnNum", typeof(int),
typeof(RectangleGrid),
new FrameworkPropertyMetadata(4));
public int ColumnNum
{
get
{
return (int)GetValue(ColumnNumProperty);
}
set
{
SetValue(ColumnNumProperty, value);
}
}
public static readonly DependencyProperty SelectRowProperty = DependencyProperty.Register("SelectRow", typeof(int),
typeof(RectangleGrid),
new FrameworkPropertyMetadata(0));
public int SelectRow
{
get
{
return (int)GetValue(SelectRowProperty);
}
set
{
SetValue(SelectRowProperty, value);
}
}
public static readonly DependencyProperty SelectColumnProperty = DependencyProperty.Register("SelectColumn", typeof(int),
typeof(RectangleGrid),
new FrameworkPropertyMetadata(0));
public int SelectColumn
{
get
{
return (int)GetValue(SelectColumnProperty);
}
set
{
SetValue(SelectColumnProperty, value);
}
}
public static readonly DependencyProperty SelectProperty = DependencyProperty.Register("Select", typeof(RectangleGridEventArgs),
typeof(RectangleGrid),
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnSelectChanged)));
public RectangleGridEventArgs Select
{
get
{
return (RectangleGridEventArgs)GetValue(SelectProperty);
}
set
{
SetValue(SelectProperty, value);
}
}
#region MouseOverBrush
public static readonly DependencyProperty MouseOverBrushProperty = DependencyProperty.Register(
"MouseOverBrush", typeof(Brush), typeof(RectangleGrid), new PropertyMetadata(null));
public Brush MouseOverBrush
{
get { return (Brush)GetValue(MouseOverBrushProperty); }
set { SetValue(MouseOverBrushProperty, value); }
}
#endregion
private Rectangle[,] rectangles;
public RectangleGrid()
{
this.Loaded += RectangleGrid_Loaded;
}
void RectangleGrid_Loaded(object sender, RoutedEventArgs e)
{
this.Loaded -= RectangleGrid_Loaded;
for (int i = 0; i < RowNum; i++)
{
RowDefinition row = new RowDefinition() { Height = new GridLength(2, GridUnitType.Auto) };
this.RowDefinitions.Add(row);
}
for (int j = 0; j < ColumnNum; j++)
{
ColumnDefinition col = new ColumnDefinition() { Width = new GridLength(2, GridUnitType.Auto) };
this.ColumnDefinitions.Add(col);
}
rectangles = new Rectangle[RowNum, ColumnNum];
for (int i = 0; i < rectangles.GetLength(0); i++)
{
for (int j = 0; j < rectangles.GetLength(1); j++)
{
Rectangle rectangle = new Rectangle();
rectangle.IsHitTestVisible = true;
rectangle.SnapsToDevicePixels = true;
rectangle.Stroke = new SolidColorBrush(Colors.Black);
rectangle.Width = 24;
rectangle.Height = 24;
rectangle.Margin = new Thickness(2);
rectangle.MouseEnter += rectangle_MouseEnter;
rectangle.MouseLeave += rectangle_MouseLeave;
rectangle.MouseLeftButtonDown += rectangle_MouseLeftButtonDown;
rectangle.Fill = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0xff, 0xff));
Grid.SetRow(rectangle, i);
Grid.SetColumn(rectangle, j);
this.Children.Add(rectangle);
rectangles[i, j] = rectangle;
}
}
}
void rectangle_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
Brush myBrush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(0xff, 0x30, 0x50, 0x68));
Brush myBrush2 = new SolidColorBrush(System.Windows.Media.Color.FromArgb(0xff, 0xff, 0xff, 0xff));
if (MouseOverBrush != null)
{
myBrush = MouseOverBrush;
}
#region
Rectangle rect = sender as Rectangle;
var rects = rectangles.Cast<Rectangle>().ToArray();
int index = Array.IndexOf(rects, rect);
int x = index / rectangles.GetLength(1);
int y = index % rectangles.GetLength(1);
FillRectangle(x, y);
#endregion
}
private void FillRectangle(int row, int column)
{
Brush myBrush = new SolidColorBrush(Color.FromArgb(0xff, 0x30, 0x50, 0x68));
Brush myBrush2 = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0xff, 0xff));
if (MouseOverBrush != null)
{
myBrush = MouseOverBrush;
}
for (int i = 0; i < rectangles.GetLength(0); i++)
{
for (int j = 0; j < rectangles.GetLength(1); j++)
{
if (i <= row && j <= column)
{
rectangles[i, j].Fill = myBrush;
}
else
{
rectangles[i, j].Fill = myBrush2;
}
}
}
}
void rectangle_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
}
void rectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Rectangle rect = sender as Rectangle;
var rects = rectangles.Cast<Rectangle>().ToArray();
int index = Array.IndexOf(rects, rect);
int x = index / rectangles.GetLength(1);
int y = index % rectangles.GetLength(1);
this.SelectRow = x + 1;
this.SelectColumn = y + 1;
this.Select = new RectangleGridEventArgs(this.SelectRow, this.SelectColumn);
}
private static void OnSelectRowChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
RectangleGrid grid = (RectangleGrid)sender;
int oldRow = (int)e.OldValue;
int newRow = (int)e.NewValue;
if (oldRow == 0 || newRow == 0)
{
grid.FillRectangle((int)e.NewValue, grid.SelectColumn);
}
//避免两次触发
var oldArgs = new RectangleGridEventArgs(oldRow, grid.SelectColumn);
var newArgs = new RectangleGridEventArgs(newRow, grid.SelectColumn);
grid.OnSelectColumnChanged(oldArgs, newArgs);
}
private static void OnSelectColumnChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
RectangleGrid grid = (RectangleGrid)sender;
int oldColumn = (int)e.OldValue;
int newColumn = (int)e.NewValue;
grid.FillRectangle(grid.SelectRow, (int)e.NewValue);
var oldArgs = new RectangleGridEventArgs(grid.SelectRow, oldColumn);
var newArgs = new RectangleGridEventArgs(grid.SelectRow, newColumn);
grid.OnSelectColumnChanged(oldArgs, newArgs);
}
private static void OnSelectChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
RectangleGrid grid = (RectangleGrid)sender;
RectangleGridEventArgs oldArgs = e.OldValue as RectangleGridEventArgs;
RectangleGridEventArgs newArgs = e.NewValue as RectangleGridEventArgs;
//grid.FillRectangle(newArgs.Row, newArgs.Column);
grid.OnSelectColumnChanged(oldArgs, newArgs);
}
public static readonly RoutedEvent SelectRowColumnChangedEvent =
EventManager.RegisterRoutedEvent("SelectRowColumnChanged", RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<RectangleGridEventArgs>), typeof(RectangleGrid));
public event RoutedPropertyChangedEventHandler<RectangleGridEventArgs> SelectRowColumnChanged
{
add { AddHandler(SelectRowColumnChangedEvent, value); }
remove { RemoveHandler(SelectRowColumnChangedEvent, value); }
}
private void OnSelectColumnChanged(RectangleGridEventArgs oldargs, RectangleGridEventArgs newargs)
{
RoutedPropertyChangedEventArgs<RectangleGridEventArgs> args = new RoutedPropertyChangedEventArgs<RectangleGridEventArgs>(oldargs, newargs);
args.RoutedEvent = RectangleGrid.SelectRowColumnChangedEvent;
RaiseEvent(args);
switch (Command)
{
case null:
return;
case RoutedCommand command:
command.Execute(CommandParameter, CommandTarget);
break;
default:
Command.Execute(CommandParameter);
break;
}
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command", typeof(ICommand), typeof(RectangleGrid), new PropertyMetadata(default(ICommand), OnCommandChanged));
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (RectangleGrid)d;
if (e.OldValue is ICommand oldCommand)
{
oldCommand.CanExecuteChanged -= ctl.CanExecuteChanged;
}
if (e.NewValue is ICommand newCommand)
{
newCommand.CanExecuteChanged += ctl.CanExecuteChanged;
}
}
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
"CommandParameter", typeof(object), typeof(RectangleGrid), new PropertyMetadata(default(object)));
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
"CommandTarget", typeof(IInputElement), typeof(RectangleGrid), new PropertyMetadata(default(IInputElement)));
public IInputElement CommandTarget
{
get => (IInputElement)GetValue(CommandTargetProperty);
set => SetValue(CommandTargetProperty, value);
}
private void CanExecuteChanged(object sender, EventArgs e)
{
if (Command == null) return;
IsEnabled = Command is RoutedCommand command
? command.CanExecute(CommandParameter, CommandTarget)
: Command.CanExecute(CommandParameter);
}
}
}

View File

@@ -0,0 +1,58 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Themes/ScrollViewer.xaml"/>
</ResourceDictionary.MergedDictionaries>
<ControlTemplate x:Key="ScrollViewerBaseControlTemplate" TargetType="controls:ScrollViewer">
<ControlTemplate.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar">
<EasingDoubleKeyFrame KeyTime="0:0:.1" Value=".8"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar">
<EasingDoubleKeyFrame KeyTime="0:0:.1" Value=".8"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Storyboard2">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar">
<EasingDoubleKeyFrame KeyTime="0:0:.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar">
<EasingDoubleKeyFrame KeyTime="0:0:.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Grid x:Name="Grid" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.RowSpan="2" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Opacity="0" Style="{StaticResource ScrollBarBaseStyle}" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
<ScrollBar x:Name="PART_HorizontalScrollBar" Opacity="0" Style="{StaticResource ScrollBarBaseStyle}" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsMouseOver,RelativeSource={RelativeSource Self}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource Storyboard2}"/>
</DataTrigger.ExitActions>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="ScrollViewerBaseStyle" TargetType="controls:ScrollViewer">
<Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template" Value="{StaticResource ScrollViewerBaseControlTemplate}"/>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,237 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace AIStudio.Wpf.ADiagram.Controls
{
public class ScrollViewer : System.Windows.Controls.ScrollViewer
{
private double _totalVerticalOffset;
private double _totalHorizontalOffset;
private bool _isRunning;
/// <summary>
/// 滚动方向
/// </summary>
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
"Orientation", typeof(Orientation), typeof(ScrollViewer), new PropertyMetadata(Orientation.Vertical));
/// <summary>
/// 滚动方向
/// </summary>
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
/// <summary>
/// 是否响应鼠标滚轮操作
/// </summary>
public static readonly DependencyProperty CanMouseWheelProperty = DependencyProperty.Register(
"CanMouseWheel", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(true));
/// <summary>
/// 是否响应鼠标滚轮操作
/// </summary>
public bool CanMouseWheel
{
get => (bool)GetValue(CanMouseWheelProperty);
set => SetValue(CanMouseWheelProperty, value);
}
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (!CanMouseWheel) return;
if (!IsInertiaEnabled)
{
if (Orientation == Orientation.Vertical)
{
base.OnMouseWheel(e);
}
else
{
_totalHorizontalOffset = HorizontalOffset;
CurrentHorizontalOffset = HorizontalOffset;
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
CurrentHorizontalOffset = _totalHorizontalOffset;
}
return;
}
e.Handled = true;
if (Orientation == Orientation.Vertical)
{
if (!_isRunning)
{
_totalVerticalOffset = VerticalOffset;
CurrentVerticalOffset = VerticalOffset;
}
_totalVerticalOffset = Math.Min(Math.Max(0, _totalVerticalOffset - e.Delta), ScrollableHeight);
ScrollToVerticalOffsetInternal(_totalVerticalOffset);
}
else
{
if (!_isRunning)
{
_totalHorizontalOffset = HorizontalOffset;
CurrentHorizontalOffset = HorizontalOffset;
}
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
ScrollToHorizontalOffsetInternal(_totalHorizontalOffset);
}
}
internal void ScrollToTopInternal(double milliseconds = 500)
{
if (!_isRunning)
{
_totalVerticalOffset = VerticalOffset;
CurrentVerticalOffset = VerticalOffset;
}
ScrollToVerticalOffsetInternal(0, milliseconds);
}
internal void ScrollToVerticalOffsetInternal(double offset, double milliseconds = 500)
{
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
animation.EasingFunction = new CubicEase
{
EasingMode = EasingMode.EaseOut
};
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s, e1) =>
{
CurrentVerticalOffset = offset;
_isRunning = false;
};
_isRunning = true;
BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
}
internal void ScrollToHorizontalOffsetInternal(double offset, double milliseconds = 500)
{
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
animation.EasingFunction = new CubicEase
{
EasingMode = EasingMode.EaseOut
};
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s, e1) =>
{
CurrentHorizontalOffset = offset;
_isRunning = false;
};
_isRunning = true;
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
}
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) =>
IsPenetrating ? null : base.HitTestCore(hitTestParameters);
/// <summary>
/// 是否支持惯性
/// </summary>
public static readonly DependencyProperty IsInertiaEnabledProperty = DependencyProperty.RegisterAttached(
"IsInertiaEnabled", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(false));
public static void SetIsInertiaEnabled(DependencyObject element, bool value)
{
element.SetValue(IsInertiaEnabledProperty, value);
}
public static bool GetIsInertiaEnabled(DependencyObject element)
{
return (bool)element.GetValue(IsInertiaEnabledProperty);
}
/// <summary>
/// 是否支持惯性
/// </summary>
public bool IsInertiaEnabled
{
get => (bool)GetValue(IsInertiaEnabledProperty);
set => SetValue(IsInertiaEnabledProperty, value);
}
/// <summary>
/// 控件是否可以穿透点击
/// </summary>
public static readonly DependencyProperty IsPenetratingProperty = DependencyProperty.RegisterAttached(
"IsPenetrating", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(false));
/// <summary>
/// 控件是否可以穿透点击
/// </summary>
public bool IsPenetrating
{
get => (bool)GetValue(IsPenetratingProperty);
set => SetValue(IsPenetratingProperty, value);
}
public static void SetIsPenetrating(DependencyObject element, bool value)
{
element.SetValue(IsPenetratingProperty, value);
}
public static bool GetIsPenetrating(DependencyObject element)
{
return (bool)element.GetValue(IsPenetratingProperty);
}
/// <summary>
/// 当前垂直滚动偏移
/// </summary>
internal static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register(
"CurrentVerticalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(0d, OnCurrentVerticalOffsetChanged));
private static void OnCurrentVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScrollViewer ctl && e.NewValue is double v)
{
ctl.ScrollToVerticalOffset(v);
}
}
/// <summary>
/// 当前垂直滚动偏移
/// </summary>
internal double CurrentVerticalOffset
{
// ReSharper disable once UnusedMember.Local
get => (double)GetValue(CurrentVerticalOffsetProperty);
set => SetValue(CurrentVerticalOffsetProperty, value);
}
/// <summary>
/// 当前水平滚动偏移
/// </summary>
internal static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register(
"CurrentHorizontalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(0d, OnCurrentHorizontalOffsetChanged));
private static void OnCurrentHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScrollViewer ctl && e.NewValue is double v)
{
ctl.ScrollToHorizontalOffset(v);
}
}
/// <summary>
/// 当前水平滚动偏移
/// </summary>
internal double CurrentHorizontalOffset
{
get => (double)GetValue(CurrentHorizontalOffsetProperty);
set => SetValue(CurrentHorizontalOffsetProperty, value);
}
}
}

View File

@@ -0,0 +1,38 @@
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.SliderRotation"
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:AIStudio.Wpf.ADiagram.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Name="sliderRotation"
Foreground="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}" BorderBrush="{DynamicResource BlackBrush}" >
<Viewbox>
<Grid>
<Canvas Name="canvas" Width="80" Height="80" HorizontalAlignment="Center" VerticalAlignment="Center">
<Ellipse Height="80" Width="80" Name="ellipseBack"
Stroke="{x:Null}"
Fill="{Binding ElementName=sliderRotation, Path=BorderBrush}"
MouseLeave="ellipseBack_MouseLeave"
MouseMove="ellipseBack_MouseMove"
MouseLeftButtonUp="ellipseBack_MouseUp"
MouseLeftButtonDown="ellipseBack_MouseDown"
StrokeThickness="0.5">
<!--<Ellipse.Effect>-->
<!--Effect外部光圈-->
<!--
<DropShadowEffect Direction="270" Color="Black" Opacity="0.5" BlurRadius="3" ShadowDepth="1"/>
</Ellipse.Effect>-->
</Ellipse>
<Ellipse Height="20" Name="handle" Stroke="#20000000" Width="20" Fill="{Binding ElementName=sliderRotation, Path=Foreground}" RenderTransformOrigin="0.5,2"
IsHitTestVisible="False" Margin="30,0,0,0">
<Ellipse.RenderTransform>
<RotateTransform x:Name="rotate" Angle="{Binding ElementName=sliderRotation, Path=Value}"/>
<!--RotateTransform能够让某对象产生旋转变化根据中心点进行顺时针旋转或逆时针旋转。-->
</Ellipse.RenderTransform>
</Ellipse>
</Canvas>
</Grid>
</Viewbox>
</UserControl>

View File

@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// SliderRotation.xaml 的交互逻辑
/// </summary>
public partial class SliderRotation : UserControl
{
#region
private Point cen; //中心点
private Point first; //初始状态位置
private Point second; //
private bool flag = false;
#endregion
#region
/// <summary>
/// 获取或设置Value数值
/// </summary>
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(
"Value",
typeof(double),
typeof(SliderRotation),
new FrameworkPropertyMetadata((double)0, new PropertyChangedCallback(ValuePropertyChangedCallback)));
#endregion
public SliderRotation()
{
InitializeComponent();
}
private static void ValuePropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
{
if (sender != null && sender is SliderRotation)
{
SliderRotation sliderRotation = sender as SliderRotation;
RoutedPropertyChangedEventArgs<object> valueArg =
new RoutedPropertyChangedEventArgs<object>(arg.OldValue, arg.NewValue, ValueChangedEvent);
sliderRotation.RaiseEvent(valueArg);
}
}
#region
public event RoutedPropertyChangedEventHandler<object> ValueChanged
{
add
{
this.AddHandler(ValueChangedEvent, value);
}
remove
{
this.RemoveHandler(ValueChangedEvent, value);
}
}
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent(
"ValueChanged",
RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<object>),
typeof(SliderRotation));
#endregion
private double GetAngle(Point point) //获取点到中心的角度 构造平面直角坐标系 计算点在该坐标系与y轴正方向的夹角
{
const double M_PI = 3.1415926535897;
if (point.X >= 0)
{
double hypotenuse = Math.Sqrt(point.X * point.X + point.Y * point.Y);
return Math.Acos(point.Y / hypotenuse) * 180 / M_PI;
}
else
{
double hypotenuse = Math.Sqrt(point.X * point.X + point.Y * point.Y);
return 360 - Math.Acos(point.Y / hypotenuse) * 180 / M_PI;
}
}
private void ellipseBack_MouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
flag = true;
cen = new Point(ellipseBack.Width / 2, ellipseBack.Height / 2);
first = new Point(e.GetPosition(canvas).X - cen.X, cen.Y - e.GetPosition(canvas).Y);
}
private void ellipseBack_MouseUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
flag = false;
}
private void ellipseBack_MouseLeave(object sender, MouseEventArgs e)
{
e.Handled = true;
flag = false;
}
private void ellipseBack_MouseMove(object sender, MouseEventArgs e)
{
e.Handled = true; //停止路由事件向上传递
if (flag)
{
second = new Point(e.GetPosition(canvas).X - cen.X, cen.Y - e.GetPosition(canvas).Y); //确定鼠标移动的点坐标(相对中心点的位置)
if (second == new Point(0, 0))
{
return;
}
double anglePointToPoint = GetAngle(second) - GetAngle(first); //得到鼠标移动之前与鼠标移动之后之间的夹角
first = second;
if (Math.Abs(anglePointToPoint) > 90) //夹角如果大于90度忽略(大于90度的夹角有可能是计算错误得出来的)
{
anglePointToPoint = 0;
}
var angle = Value + anglePointToPoint;
if (angle < 0)
{
angle += 360;
}
angle = angle % 360;
Value = Math.Round(angle, 0); //计算出旋转角度
}
}
}
}

View File

@@ -0,0 +1,181 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:interactivity="clr-namespace:Util.Controls.Handy.Interactivity">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Basic/Paths.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Basic/Converters.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Themes/Button.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Themes/RepeatButton.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Themes/ToggleButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
<ContextMenu x:Key="TabItemMenu" x:Shared="False">
<MenuItem Command="interactivity:ControlCommands.Close" Header="Close"/>
<MenuItem Command="interactivity:ControlCommands.CloseAll" Header="CloseAll"/>
<MenuItem Command="interactivity:ControlCommands.CloseOther" Header="CloseOther"/>
</ContextMenu>
<Style TargetType="controls:TabItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.Text}"/>
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.ThemeBackground}"/>
<Setter Property="BorderThickness" Value="1,0,1,1"/>
<Setter Property="BorderBrush" Value="{DynamicResource MahApps.Brushes.Control.Border}"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="10,0,0,0"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Menu" Value="{StaticResource TabItemMenu}"/>
<Setter Property="controls:IconElement.Width" Value="16"/>
<Setter Property="controls:IconElement.Height" Value="16"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Background="Transparent" Text="{Binding Header,RelativeSource={RelativeSource AncestorType=controls:TabItem}}"/>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:TabItem">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true" ContextMenu="{TemplateBinding Menu}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="3" BorderThickness="{TemplateBinding BorderThickness}" x:Name="mainBorder" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Margin="0">
<Border Margin="0,0,0,-1" x:Name="innerBorder" Background="{DynamicResource MahApps.Brushes.Gray8}" Visibility="Collapsed"/>
</Border>
<Path x:Name="PathMain" Margin="10,0,0,0" Grid.Column="0" Width="{TemplateBinding controls:IconElement.Width}" Height="{TemplateBinding controls:IconElement.Height}" Fill="{TemplateBinding Foreground}" SnapsToDevicePixels="True" Stretch="Uniform" Data="{TemplateBinding controls:IconElement.Geometry}"/>
<ContentPresenter Grid.Column="1" x:Name="contentPresenter" ContentSource="Header" Focusable="False" HorizontalAlignment="Stretch" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
<Border Name="BorderMask" Grid.Column="1" HorizontalAlignment="Right" Width="20" Background="{TemplateBinding Background}">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
<GradientStop Color="White" Offset="1"/>
<GradientStop Offset="0"/>
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<Button Grid.Column="2" Focusable="False" Command="interactivity:ControlCommands.Close" Visibility="{TemplateBinding ShowCloseButton,Converter={StaticResource Boolean2VisibilityConverter}}" Background="Transparent" Style="{StaticResource ButtonCustom}" Width="28">
<Path Fill="{DynamicResource MahApps.Brushes.Text}" Width="8" Height="8" Style="{StaticResource ClosePathStyle}"/>
</Button>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Visibility" TargetName="innerBorder" Value="Visible"/>
<Setter Property="Background" TargetName="BorderMask" Value="{DynamicResource MahApps.Brushes.Gray8}"/>
</Trigger>
<Trigger Property="controls:IconElement.Geometry" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" TargetName="PathMain"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="TabControlPlusTemplate" TargetType="controls:TabControl">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Background="{TemplateBinding Background}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}">
<controls:TabPanel MinHeight="{TemplateBinding TabItemHeight}" TabItemHeight="{TemplateBinding TabItemHeight}" TabItemWidth="{TemplateBinding TabItemWidth}" IsTabFillEnabled="{TemplateBinding IsTabFillEnabled}" Margin="0,0,-1,-1" x:Name="PART_HeaderPanel" HorizontalAlignment="Left" Background="{DynamicResource SecondaryTextBrush}" IsItemsHost="true" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1">
<interactivity:Interaction.Behaviors>
<interactivity:FluidMoveBehavior AppliesTo="Children" Duration="{Binding FluidMoveDuration,ElementName=PART_HeaderPanel}">
<interactivity:FluidMoveBehavior.EaseX>
<CubicEase EasingMode="EaseOut"/>
</interactivity:FluidMoveBehavior.EaseX>
</interactivity:FluidMoveBehavior>
</interactivity:Interaction.Behaviors>
</controls:TabPanel>
</Border>
<Border x:Name="contentPanel" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<Border Visibility="{Binding Visibility,ElementName=PART_OverflowButton}" Margin="0,-1,0,0" Grid.Row="0" Grid.Column="0" BorderThickness="1,0,0,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Background="{DynamicResource MahApps.Brushes.Gray8}" HorizontalAlignment="Right">
<controls:ContextMenuToggleButton x:Name="PART_OverflowButton" Visibility="Collapsed" Style="{StaticResource ToggleButtonIconTransparent}" controls:IconSwitchElement.Geometry="{StaticResource DownGeometry}" controls:IconSwitchElement.GeometrySelected="{StaticResource UpGeometry}"/>
</Border>
</Grid>
</Border>
</ControlTemplate>
<ControlTemplate x:Key="TabControlPlusScrollableTemplate" TargetType="controls:TabControl">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Visibility="{TemplateBinding ShowScrollButton,Converter={StaticResource Boolean2VisibilityConverter}}" Margin="0,-1,0,0" Grid.Row="0" Grid.Column="0" BorderThickness="0,0,1,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Background="{DynamicResource MahApps.Brushes.Gray8}" HorizontalAlignment="Left" Panel.ZIndex="2">
<Border.CacheMode>
<BitmapCache SnapsToDevicePixels="True"/>
</Border.CacheMode>
<RepeatButton Focusable="False" Style="{StaticResource RepeatButtonIcon}" Padding="8" controls:IconElement.Geometry="{StaticResource LeftGeometry}" Foreground="{DynamicResource MahApps.Brushes.Text}" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" x:Name="PART_ScrollButtonLeft"/>
</Border>
<controls:ScrollViewer HorizontalScrollBarVisibility="Hidden" CanMouseWheel="True" Orientation="Horizontal" IsInertiaEnabled="True" Grid.Row="0" Grid.Column="1" IsDeferredScrollingEnabled="True" x:Name="PART_OverflowScrollviewer">
<Border Background="{TemplateBinding Background}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Name="PART_HeaderBorder">
<controls:TabPanel MinHeight="{TemplateBinding TabItemHeight}" TabItemHeight="{TemplateBinding TabItemHeight}" TabItemWidth="{TemplateBinding TabItemWidth}" IsTabFillEnabled="{TemplateBinding IsTabFillEnabled}" Margin="0,0,-1,-1" x:Name="PART_HeaderPanel" HorizontalAlignment="Left" Background="{DynamicResource SecondaryTextBrush}" IsItemsHost="true" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1">
<interactivity:Interaction.Behaviors>
<interactivity:FluidMoveBehavior AppliesTo="Children" Duration="{Binding FluidMoveDuration,ElementName=PART_HeaderPanel}">
<interactivity:FluidMoveBehavior.EaseX>
<CubicEase EasingMode="EaseOut"/>
</interactivity:FluidMoveBehavior.EaseX>
</interactivity:FluidMoveBehavior>
</interactivity:Interaction.Behaviors>
</controls:TabPanel>
</Border>
</controls:ScrollViewer>
<Border Margin="0,-1,0,0" Grid.Row="0" Grid.Column="2" BorderThickness="1,0,0,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Background="{DynamicResource MahApps.Brushes.Gray8}" HorizontalAlignment="Right">
<Border.CacheMode>
<BitmapCache SnapsToDevicePixels="True"/>
</Border.CacheMode>
<StackPanel Orientation="Horizontal">
<RepeatButton Focusable="False" Visibility="{TemplateBinding ShowScrollButton,Converter={StaticResource Boolean2VisibilityConverter}}" Style="{StaticResource RepeatButtonIcon}" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Padding="8" controls:IconElement.Geometry="{StaticResource RightGeometry}" Foreground="{DynamicResource MahApps.Brushes.Text}" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" x:Name="PART_ScrollButtonRight"/>
<Border Visibility="{Binding Visibility,ElementName=PART_OverflowButton}" Width="1" Background="{DynamicResource MahApps.Brushes.Control.Border}"/>
<controls:ContextMenuToggleButton x:Name="PART_OverflowButton" Visibility="Collapsed" Style="{StaticResource ToggleButtonIconTransparent}" controls:IconSwitchElement.Geometry="{StaticResource DownGeometry}" controls:IconSwitchElement.GeometrySelected="{StaticResource UpGeometry}"/>
</StackPanel>
</Border>
<Border x:Name="contentPanel" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
</Border>
</ControlTemplate>
<Style TargetType="controls:TabControl">
<Setter Property="Padding" Value="0"/>
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Gray8}"/>
<Setter Property="BorderBrush" Value="{DynamicResource MahApps.Brushes.Control.Border}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template" Value="{StaticResource TabControlPlusTemplate}"/>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsScrollable" Value="True"/>
<Condition Property="IsTabFillEnabled" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="Template" Value="{StaticResource TabControlPlusScrollableTemplate}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,443 @@
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace AIStudio.Wpf.ADiagram.Controls
{
[TemplatePart(Name = OverflowButtonKey, Type = typeof(ContextMenuToggleButton))]
[TemplatePart(Name = HeaderPanelKey, Type = typeof(TabPanel))]
[TemplatePart(Name = OverflowScrollviewer, Type = typeof(ScrollViewer))]
[TemplatePart(Name = ScrollButtonLeft, Type = typeof(ButtonBase))]
[TemplatePart(Name = ScrollButtonRight, Type = typeof(ButtonBase))]
[TemplatePart(Name = HeaderBorder, Type = typeof(System.Windows.Controls.Border))]
public class TabControl : System.Windows.Controls.TabControl
{
private const string OverflowButtonKey = "PART_OverflowButton";
private const string HeaderPanelKey = "PART_HeaderPanel";
private const string OverflowScrollviewer = "PART_OverflowScrollviewer";
private const string ScrollButtonLeft = "PART_ScrollButtonLeft";
private const string ScrollButtonRight = "PART_ScrollButtonRight";
private const string HeaderBorder = "PART_HeaderBorder";
private ContextMenuToggleButton _buttonOverflow;
internal TabPanel HeaderPanel { get; private set; }
private ScrollViewer _scrollViewerOverflow;
private ButtonBase _buttonScrollLeft;
private ButtonBase _buttonScrollRight;
private System.Windows.Controls.Border _headerBorder;
/// <summary>
/// 是否为内部操作
/// </summary>
internal bool IsInternalAction;
/// <summary>
/// 是否启用动画
/// </summary>
public static readonly DependencyProperty IsAnimationEnabledProperty = DependencyProperty.Register(
"IsAnimationEnabled", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
/// <summary>
/// 是否启用动画
/// </summary>
public bool IsAnimationEnabled
{
get => (bool)GetValue(IsAnimationEnabledProperty);
set => SetValue(IsAnimationEnabledProperty, value);
}
/// <summary>
/// 是否可以拖动
/// </summary>
public static readonly DependencyProperty IsDraggableProperty = DependencyProperty.Register(
"IsDraggable", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
/// <summary>
/// 是否可以拖动
/// </summary>
public bool IsDraggable
{
get => (bool)GetValue(IsDraggableProperty);
set => SetValue(IsDraggableProperty, value);
}
/// <summary>
/// 是否显示关闭按钮
/// </summary>
public static readonly DependencyProperty ShowCloseButtonProperty = DependencyProperty.RegisterAttached(
"ShowCloseButton", typeof(bool), typeof(TabControl), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
public static void SetShowCloseButton(DependencyObject element, bool value)
=> element.SetValue(ShowCloseButtonProperty, value);
public static bool GetShowCloseButton(DependencyObject element)
=> (bool) element.GetValue(ShowCloseButtonProperty);
/// <summary>
/// 是否显示关闭按钮
/// </summary>
public bool ShowCloseButton
{
get => (bool)GetValue(ShowCloseButtonProperty);
set => SetValue(ShowCloseButtonProperty, value);
}
/// <summary>
/// 是否显示上下文菜单
/// </summary>
public static readonly DependencyProperty ShowContextMenuProperty = DependencyProperty.RegisterAttached(
"ShowContextMenu", typeof(bool), typeof(TabControl), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
public static void SetShowContextMenu(DependencyObject element, bool value)
=> element.SetValue(ShowContextMenuProperty, value);
public static bool GetShowContextMenu(DependencyObject element)
=> (bool) element.GetValue(ShowContextMenuProperty);
/// <summary>
/// 是否显示上下文菜单
/// </summary>
public bool ShowContextMenu
{
get => (bool)GetValue(ShowContextMenuProperty);
set => SetValue(ShowContextMenuProperty, value);
}
/// <summary>
/// 是否将标签填充
/// </summary>
public static readonly DependencyProperty IsTabFillEnabledProperty = DependencyProperty.Register(
"IsTabFillEnabled", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
/// <summary>
/// 是否将标签填充
/// </summary>
public bool IsTabFillEnabled
{
get => (bool)GetValue(IsTabFillEnabledProperty);
set => SetValue(IsTabFillEnabledProperty, value);
}
/// <summary>
/// 标签宽度
/// </summary>
public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register(
"TabItemWidth", typeof(double), typeof(TabControl), new PropertyMetadata(200.0));
/// <summary>
/// 标签宽度
/// </summary>
public double TabItemWidth
{
get => (double)GetValue(TabItemWidthProperty);
set => SetValue(TabItemWidthProperty, value);
}
/// <summary>
/// 标签高度
/// </summary>
public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register(
"TabItemHeight", typeof(double), typeof(TabControl), new PropertyMetadata(30.0));
/// <summary>
/// 标签高度
/// </summary>
public double TabItemHeight
{
get => (double)GetValue(TabItemHeightProperty);
set => SetValue(TabItemHeightProperty, value);
}
/// <summary>
/// 是否可以滚动
/// </summary>
public static readonly DependencyProperty IsScrollableProperty = DependencyProperty.Register(
"IsScrollable", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
/// <summary>
/// 是否可以滚动
/// </summary>
public bool IsScrollable
{
get => (bool) GetValue(IsScrollableProperty);
set => SetValue(IsScrollableProperty, value);
}
/// <summary>
/// 是否显示溢出按钮
/// </summary>
public static readonly DependencyProperty ShowOverflowButtonProperty = DependencyProperty.Register(
"ShowOverflowButton", typeof(bool), typeof(TabControl), new PropertyMetadata(true));
/// <summary>
/// 是否显示溢出按钮
/// </summary>
public bool ShowOverflowButton
{
get => (bool) GetValue(ShowOverflowButtonProperty);
set => SetValue(ShowOverflowButtonProperty, value);
}
/// <summary>
/// 是否显示滚动按钮
/// </summary>
public static readonly DependencyProperty ShowScrollButtonProperty = DependencyProperty.Register(
"ShowScrollButton", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
/// <summary>
/// 是否显示滚动按钮
/// </summary>
public bool ShowScrollButton
{
get => (bool) GetValue(ShowScrollButtonProperty);
set => SetValue(ShowScrollButtonProperty, value);
}
/// <summary>
/// 可见的标签数量
/// </summary>
private int _itemShowCount;
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
if (HeaderPanel == null)
{
IsInternalAction = false;
return;
}
UpdateOverflowButton();
if (IsInternalAction)
{
IsInternalAction = false;
return;
}
if (IsAnimationEnabled)
{
HeaderPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, new Duration(TimeSpan.FromMilliseconds(200)));
}
else
{
HeaderPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
}
if (e.Action == NotifyCollectionChangedAction.Add)
{
for (var i = 0; i < Items.Count; i++)
{
if (!(ItemContainerGenerator.ContainerFromIndex(i) is TabItem item)) return;
item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
item.TabPanel = HeaderPanel;
}
}
_headerBorder?.InvalidateMeasure();
IsInternalAction = false;
}
public override void OnApplyTemplate()
{
if (_buttonOverflow != null)
{
if (_buttonOverflow.Menu != null)
{
_buttonOverflow.Menu.Closed -= Menu_Closed;
_buttonOverflow.Menu = null;
}
_buttonOverflow.Click -= ButtonOverflow_Click;
}
if (_buttonScrollLeft != null) _buttonScrollLeft.Click -= ButtonScrollLeft_Click;
if (_buttonScrollRight != null) _buttonScrollRight.Click -= ButtonScrollRight_Click;
base.OnApplyTemplate();
HeaderPanel = GetTemplateChild(HeaderPanelKey) as TabPanel;
if (IsTabFillEnabled) return;
_buttonOverflow = GetTemplateChild(OverflowButtonKey) as ContextMenuToggleButton;
_scrollViewerOverflow = GetTemplateChild(OverflowScrollviewer) as ScrollViewer;
_buttonScrollLeft = GetTemplateChild(ScrollButtonLeft) as ButtonBase;
_buttonScrollRight = GetTemplateChild(ScrollButtonRight) as ButtonBase;
_headerBorder = GetTemplateChild(HeaderBorder) as System.Windows.Controls.Border;
if (_buttonScrollLeft != null) _buttonScrollLeft.Click += ButtonScrollLeft_Click;
if (_buttonScrollRight != null) _buttonScrollRight.Click += ButtonScrollRight_Click;
if (_buttonOverflow != null)
{
var menu = new System.Windows.Controls.ContextMenu
{
Placement = PlacementMode.Bottom,
PlacementTarget = _buttonOverflow
};
menu.Closed += Menu_Closed;
_buttonOverflow.Menu = menu;
_buttonOverflow.Click += ButtonOverflow_Click;
}
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
UpdateOverflowButton();
}
private void UpdateOverflowButton()
{
if (!IsTabFillEnabled)
{
_itemShowCount = (int)(ActualWidth / TabItemWidth);
if (_buttonOverflow != null)
{
_buttonOverflow.Visibility = (ShowOverflowButton && Items.Count > 0 && Items.Count >= _itemShowCount) ? Visibility.Visible : Visibility.Collapsed;
}
}
}
private void Menu_Closed(object sender, RoutedEventArgs e) => _buttonOverflow.IsChecked = false;
private void ButtonScrollRight_Click(object sender, RoutedEventArgs e) =>
_scrollViewerOverflow.ScrollToHorizontalOffsetInternal(Math.Min(
_scrollViewerOverflow.CurrentHorizontalOffset + TabItemWidth, _scrollViewerOverflow.ScrollableWidth));
private void ButtonScrollLeft_Click(object sender, RoutedEventArgs e) =>
_scrollViewerOverflow.ScrollToHorizontalOffsetInternal(Math.Max(
_scrollViewerOverflow.CurrentHorizontalOffset - TabItemWidth, 0));
private void ButtonOverflow_Click(object sender, RoutedEventArgs e)
{
if (_buttonOverflow.IsChecked == true)
{
_buttonOverflow.Menu.Items.Clear();
for (var i = 0; i < Items.Count; i++)
{
if(!(ItemContainerGenerator.ContainerFromIndex(i) is TabItem item)) continue;
var menuItem = new System.Windows.Controls.MenuItem
{
HeaderStringFormat = ItemStringFormat,
HeaderTemplate = ItemTemplate,
HeaderTemplateSelector = ItemTemplateSelector,
Header = item.Header,
Width = TabItemWidth,
IsChecked = item.IsSelected,
IsCheckable = true
};
menuItem.Click += delegate
{
_buttonOverflow.IsChecked = false;
var list = GetActualList();
if (list == null) return;
var actualItem = ItemContainerGenerator.ItemFromContainer(item);
if (actualItem == null) return;
var index = list.IndexOf(actualItem);
if (index >= _itemShowCount)
{
list.Remove(actualItem);
list.Insert(0, actualItem);
if (IsAnimationEnabled)
{
HeaderPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, new Duration(TimeSpan.FromMilliseconds(200)));
}
else
{
HeaderPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
}
HeaderPanel.ForceUpdate = true;
HeaderPanel.Measure(new Size(HeaderPanel.DesiredSize.Width, ActualHeight));
HeaderPanel.ForceUpdate = false;
SetCurrentValue(SelectedIndexProperty, 0);
}
item.IsSelected = true;
};
_buttonOverflow.Menu.Items.Add(menuItem);
}
}
}
internal double GetHorizontalOffset() => _scrollViewerOverflow?.CurrentHorizontalOffset ?? 0;
internal void UpdateScroll() => _scrollViewerOverflow?.RaiseEvent(new MouseWheelEventArgs(Mouse.PrimaryDevice, Environment.TickCount, 0)
{
RoutedEvent = MouseWheelEvent
});
internal void CloseAllItems() => CloseOtherItems(null);
internal void CloseOtherItems(TabItem currentItem)
{
var actualItem = currentItem != null ? ItemContainerGenerator.ItemFromContainer(currentItem) : null;
var list = GetActualList();
if (list == null) return;
IsInternalAction = true;
for (var i = 0; i < Items.Count; i++)
{
var item = list[i];
if (!Equals(item, actualItem) && item != null)
{
var argsClosing = new CancelRoutedEventArgs(TabItem.ClosingEvent, item);
if (!(ItemContainerGenerator.ContainerFromItem(item) is TabItem tabItem)) continue;
tabItem.RaiseEvent(argsClosing);
if (argsClosing.Cancel) return;
tabItem.RaiseEvent(new RoutedEventArgs(TabItem.ClosedEvent, item));
list.Remove(item);
i--;
}
}
SetCurrentValue(SelectedIndexProperty, Items.Count == 0 ? -1 : 0);
}
internal IList GetActualList()
{
IList list;
if (ItemsSource != null)
{
list = ItemsSource as IList;
}
else
{
list = Items;
}
return list;
}
protected override bool IsItemItsOwnContainerOverride(object item) => item is TabItem;
protected override DependencyObject GetContainerForItemOverride() => new TabItem();
}
}

View File

@@ -0,0 +1,467 @@
using System;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace AIStudio.Wpf.ADiagram.Controls
{
public class TabItem : System.Windows.Controls.TabItem
{
/// <summary>
/// 动画速度
/// </summary>
private const int AnimationSpeed = 150;
/// <summary>
/// 选项卡是否处于拖动状态
/// </summary>
private static bool ItemIsDragging;
/// <summary>
/// 选项卡是否等待被拖动
/// </summary>
private bool _isWaiting;
/// <summary>
/// 拖动中的选项卡坐标
/// </summary>
private Point _dragPoint;
/// <summary>
/// 鼠标按下时选项卡位置
/// </summary>
private int _mouseDownIndex;
/// <summary>
/// 鼠标按下时选项卡横向偏移
/// </summary>
private double _mouseDownOffsetX;
/// <summary>
/// 鼠标按下时的坐标
/// </summary>
private Point _mouseDownPoint;
/// <summary>
/// 右侧可移动的最大值
/// </summary>
private double _maxMoveRight;
/// <summary>
/// 左侧可移动的最大值
/// </summary>
private double _maxMoveLeft;
/// <summary>
/// 选项卡宽度
/// </summary>
public double ItemWidth { get; internal set; }
/// <summary>
/// 选项卡拖动等待距离在鼠标移动了超过20个像素无关单位后选项卡才开始被拖动
/// </summary>
private const double WaitLength = 20;
/// <summary>
/// 选项卡是否处于拖动状态
/// </summary>
private bool _isDragging;
/// <summary>
/// 选项卡是否已经被拖动
/// </summary>
private bool _isDragged;
/// <summary>
/// 目标横向位移
/// </summary>
internal double TargetOffsetX { get; set; }
/// <summary>
/// 当前编号
/// </summary>
private int _currentIndex;
/// <summary>
/// 标签容器横向滚动距离
/// </summary>
private double _scrollHorizontalOffset;
private TabPanel _tabPanel;
/// <summary>
/// 标签容器
/// </summary>
internal TabPanel TabPanel
{
get
{
if (_tabPanel == null && TabControlParent != null)
{
_tabPanel = TabControlParent.HeaderPanel;
}
return _tabPanel;
}
set => _tabPanel = value;
}
/// <summary>
/// 当前编号
/// </summary>
internal int CurrentIndex
{
get => _currentIndex;
set
{
if (_currentIndex == value || value < 0) return;
var oldIndex = _currentIndex;
_currentIndex = value;
UpdateItemOffsetX(oldIndex);
}
}
/// <summary>
/// 是否显示关闭按钮
/// </summary>
public static readonly DependencyProperty ShowCloseButtonProperty =
TabControl.ShowCloseButtonProperty.AddOwner(typeof(TabItem));
/// <summary>
/// 是否显示关闭按钮
/// </summary>
public bool ShowCloseButton
{
get => (bool)GetValue(ShowCloseButtonProperty);
set => SetValue(ShowCloseButtonProperty, value);
}
public static void SetShowCloseButton(DependencyObject element, bool value)
=> element.SetValue(ShowCloseButtonProperty, value);
public static bool GetShowCloseButton(DependencyObject element)
=> (bool)element.GetValue(ShowCloseButtonProperty);
/// <summary>
/// 是否显示上下文菜单
/// </summary>
public static readonly DependencyProperty ShowContextMenuProperty =
TabControl.ShowContextMenuProperty.AddOwner(typeof(TabItem), new FrameworkPropertyMetadata(OnShowContextMenuChanged));
private static void OnShowContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (TabItem) d;
if (ctl.Menu != null)
{
var show = (bool)e.NewValue;
ctl.Menu.IsEnabled = show;
ctl.Menu.Show(show);
}
}
/// <summary>
/// 是否显示上下文菜单
/// </summary>
public bool ShowContextMenu
{
get => (bool) GetValue(ShowContextMenuProperty);
set => SetValue(ShowContextMenuProperty, value);
}
public static void SetShowContextMenu(DependencyObject element, bool value)
=> element.SetValue(ShowContextMenuProperty, value);
public static bool GetShowContextMenu(DependencyObject element)
=> (bool)element.GetValue(ShowContextMenuProperty);
public static readonly DependencyProperty MenuProperty = DependencyProperty.Register(
"Menu", typeof(System.Windows.Controls.ContextMenu), typeof(TabItem), new PropertyMetadata(default(System.Windows.Controls.ContextMenu), OnMenuChanged));
private static void OnMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (TabItem) d;
ctl.OnMenuChanged(e.NewValue as System.Windows.Controls.ContextMenu);
}
private void OnMenuChanged(System.Windows.Controls.ContextMenu menu)
{
if (IsLoaded && menu != null)
{
var parent = TabControlParent;
if (parent == null) return;
var item = parent.ItemContainerGenerator.ItemFromContainer(this);
menu.DataContext = item;
menu.SetBinding(IsEnabledProperty, new Binding(ShowContextMenuProperty.Name)
{
Source = this
});
menu.SetBinding(VisibilityProperty, new Binding(ShowContextMenuProperty.Name)
{
Source = this,
Converter = ResourceHelper.GetResource<IValueConverter>("Boolean2VisibilityConverter")
});
}
}
public System.Windows.Controls.ContextMenu Menu
{
get => (System.Windows.Controls.ContextMenu) GetValue(MenuProperty);
set => SetValue(MenuProperty, value);
}
/// <summary>
/// 更新选项卡横向偏移
/// </summary>
/// <param name="oldIndex"></param>
private void UpdateItemOffsetX(int oldIndex)
{
if (!_isDragging) return;
var moveItem = TabPanel.ItemDic[CurrentIndex];
moveItem.CurrentIndex -= CurrentIndex - oldIndex;
var offsetX = moveItem.TargetOffsetX;
var resultX = offsetX + (oldIndex - CurrentIndex) * ItemWidth;
TabPanel.ItemDic[CurrentIndex] = this;
TabPanel.ItemDic[moveItem.CurrentIndex] = moveItem;
moveItem.CreateAnimation(offsetX, resultX);
}
public TabItem()
{
CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
CommandBindings.Add(new CommandBinding(ControlCommands.CloseAll,
(s, e) => { TabControlParent.CloseAllItems(); }));
CommandBindings.Add(new CommandBinding(ControlCommands.CloseOther,
(s, e) => { TabControlParent.CloseOtherItems(this); }));
Loaded += (s, e) => OnMenuChanged(Menu);
}
private Util.Controls.Handy.TabControls.TabControl TabControlParent => System.Windows.Controls.ItemsControl.ItemsControlFromItemContainer(this) as TabControl;
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
{
base.OnMouseRightButtonDown(e);
IsSelected = true;
Focus();
}
protected override void OnHeaderChanged(object oldHeader, object newHeader)
{
base.OnHeaderChanged(oldHeader, newHeader);
if (TabPanel != null)
{
TabPanel.ForceUpdate = true;
InvalidateMeasure();
TabPanel.ForceUpdate = true;
}
}
internal void Close()
{
var parent = TabControlParent;
if (parent == null) return;
var item = parent.ItemContainerGenerator.ItemFromContainer(this);
var argsClosing = new CancelRoutedEventArgs(ClosingEvent, item);
RaiseEvent(argsClosing);
if (argsClosing.Cancel) return;
TabPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, parent.IsAnimationEnabled
? new Duration(TimeSpan.FromMilliseconds(200))
: new Duration(TimeSpan.FromMilliseconds(1)));
parent.IsInternalAction = true;
RaiseEvent(new RoutedEventArgs(ClosedEvent, item));
var list = parent.GetActualList();
list?.Remove(item);
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
var parent = TabControlParent;
if (parent == null) return;
if (parent.IsDraggable && !ItemIsDragging && !_isDragging)
{
parent.UpdateScroll();
TabPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
_mouseDownOffsetX = RenderTransform.Value.OffsetX;
_scrollHorizontalOffset = parent.GetHorizontalOffset();
var mx = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
_mouseDownIndex = CalLocationIndex(mx);
var subIndex = _mouseDownIndex - CalLocationIndex(_scrollHorizontalOffset);
_maxMoveLeft = -subIndex * ItemWidth;
_maxMoveRight = parent.ActualWidth - ActualWidth + _maxMoveLeft;
_isDragging = true;
ItemIsDragging = true;
_isWaiting = true;
_dragPoint = e.GetPosition(parent);
_dragPoint = new Point(_dragPoint.X + _scrollHorizontalOffset, _dragPoint.Y);
_mouseDownPoint = _dragPoint;
CaptureMouse();
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (ItemIsDragging && _isDragging)
{
var parent = TabControlParent;
if (parent == null) return;
var subX = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
CurrentIndex = CalLocationIndex(subX);
var p = e.GetPosition(parent);
p = new Point(p.X + _scrollHorizontalOffset, p.Y);
var subLeft = p.X - _dragPoint.X;
var totalLeft = p.X - _mouseDownPoint.X;
if (Math.Abs(subLeft) <= WaitLength && _isWaiting) return;
_isWaiting = false;
_isDragged = true;
var left = subLeft + RenderTransform.Value.OffsetX;
if (totalLeft < _maxMoveLeft)
{
left = _maxMoveLeft + _mouseDownOffsetX;
}
else if (totalLeft > _maxMoveRight)
{
left = _maxMoveRight + _mouseDownOffsetX;
}
var t = new TranslateTransform(left, 0);
RenderTransform = t;
_dragPoint = p;
}
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
ReleaseMouseCapture();
if (_isDragged)
{
var parent = TabControlParent;
if (parent == null) return;
var subX = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
var index = CalLocationIndex(subX);
var left = index * ItemWidth;
var offsetX = RenderTransform.Value.OffsetX;
CreateAnimation(offsetX, offsetX - subX + left, index);
}
_isDragging = false;
ItemIsDragging = false;
_isDragged = false;
}
/// <summary>
/// 创建动画
/// </summary>
internal void CreateAnimation(double offsetX, double resultX, int index = -1)
{
var parent = TabControlParent;
void AnimationCompleted()
{
RenderTransform = new TranslateTransform(resultX, 0);
if (index == -1) return;
var list = parent.GetActualList();
if (list == null) return;
var item = parent.ItemContainerGenerator.ItemFromContainer(this);
if (item == null) return;
TabPanel.CanUpdate = false;
parent.IsInternalAction = true;
list.Remove(item);
parent.IsInternalAction = true;
list.Insert(index, item);
TabPanel.CanUpdate = true;
TabPanel.ForceUpdate = true;
TabPanel.Measure(new Size(TabPanel.DesiredSize.Width, ActualHeight));
TabPanel.ForceUpdate = false;
Focus();
IsSelected = true;
if (!IsMouseCaptured)
{
parent.SetCurrentValue(Selector.SelectedIndexProperty, _currentIndex);
}
}
TargetOffsetX = resultX;
if (!parent.IsAnimationEnabled)
{
AnimationCompleted();
return;
}
var animation = AnimationHelper.CreateAnimation(resultX, AnimationSpeed);
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s1, e1) => AnimationCompleted();
var f = new TranslateTransform(offsetX, 0);
RenderTransform = f;
f.BeginAnimation(TranslateTransform.XProperty, animation, HandoffBehavior.Compose);
}
/// <summary>
/// 计算选项卡当前合适的位置编号
/// </summary>
/// <param name="left"></param>
/// <returns></returns>
private int CalLocationIndex(double left)
{
if (_isWaiting)
{
return CurrentIndex;
}
var maxIndex = TabControlParent.Items.Count - 1;
var div = (int)(left / ItemWidth);
var rest = left % ItemWidth;
var result = rest / ItemWidth > .5 ? div + 1 : div;
return result > maxIndex ? maxIndex : result;
}
public static readonly RoutedEvent ClosingEvent = EventManager.RegisterRoutedEvent("Closing", RoutingStrategy.Bubble, typeof(EventHandler), typeof(TabItem));
public event EventHandler Closing
{
add => AddHandler(ClosingEvent, value);
remove => RemoveHandler(ClosingEvent, value);
}
public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble, typeof(EventHandler), typeof(TabItem));
public event EventHandler Closed
{
add => AddHandler(ClosedEvent, value);
remove => RemoveHandler(ClosedEvent, value);
}
}
}

View File

@@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
namespace AIStudio.Wpf.ADiagram.Controls
{
public class TabPanel : System.Windows.Controls.Panel
{
private int _itemCount;
/// <summary>
/// 是否可以更新
/// </summary>
internal bool CanUpdate = true;
/// <summary>
/// 选项卡字典
/// </summary>
internal Dictionary<int, TabItem> ItemDic = new Dictionary<int, TabItem>();
/// <summary>
/// 流式行为持续时间
/// </summary>
public static readonly DependencyProperty FluidMoveDurationProperty = DependencyProperty.Register(
"FluidMoveDuration", typeof(Duration), typeof(TabPanel), new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(200))));
/// <summary>
/// 流式行为持续时间
/// </summary>
public Duration FluidMoveDuration
{
get => (Duration)GetValue(FluidMoveDurationProperty);
set => SetValue(FluidMoveDurationProperty, value);
}
/// <summary>
/// 是否将标签填充
/// </summary>
public static readonly DependencyProperty IsTabFillEnabledProperty = DependencyProperty.Register(
"IsTabFillEnabled", typeof(bool), typeof(TabPanel), new PropertyMetadata(ValueBoxes.FalseBox));
/// <summary>
/// 是否将标签填充
/// </summary>
public bool IsTabFillEnabled
{
get => (bool)GetValue(IsTabFillEnabledProperty);
set => SetValue(IsTabFillEnabledProperty, value);
}
/// <summary>
/// 标签宽度
/// </summary>
public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register(
"TabItemWidth", typeof(double), typeof(TabPanel), new PropertyMetadata(200.0));
/// <summary>
/// 标签宽度
/// </summary>
public double TabItemWidth
{
get => (double)GetValue(TabItemWidthProperty);
set => SetValue(TabItemWidthProperty, value);
}
/// <summary>
/// 标签高度
/// </summary>
public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register(
"TabItemHeight", typeof(double), typeof(TabPanel), new PropertyMetadata(30.0));
/// <summary>
/// 标签高度
/// </summary>
public double TabItemHeight
{
get => (double)GetValue(TabItemHeightProperty);
set => SetValue(TabItemHeightProperty, value);
}
/// <summary>
/// 是否可以强制更新
/// </summary>
internal bool ForceUpdate;
private Size _oldSize;
/// <summary>
/// 是否已经加载
/// </summary>
private bool _isLoaded;
protected override Size MeasureOverride(Size constraint)
{
if ((_itemCount == InternalChildren.Count || !CanUpdate) && !ForceUpdate) return _oldSize;
constraint.Height = TabItemHeight;
_itemCount = InternalChildren.Count;
var size = new Size();
ItemDic.Clear();
var count = InternalChildren.Count;
if (count == 0)
{
_oldSize = new Size();
return _oldSize;
}
constraint.Width += InternalChildren.Count;
var itemWidth = .0;
var arr = new int[count];
if (!IsTabFillEnabled)
{
itemWidth = TabItemWidth;
}
else
{
if (TemplatedParent is TabControl tabControl)
{
arr = ArithmeticHelper.DivideInt2Arr((int)tabControl.ActualWidth + InternalChildren.Count, count);
}
}
for (var index = 0; index < count; index++)
{
if (IsTabFillEnabled)
{
itemWidth = arr[index];
}
if (InternalChildren[index] is TabItem tabItem)
{
tabItem.RenderTransform = new TranslateTransform();
tabItem.MaxWidth = itemWidth;
var rect = new Rect
{
X = size.Width - tabItem.BorderThickness.Left,
Width = itemWidth,
Height = TabItemHeight
};
tabItem.Arrange(rect);
tabItem.ItemWidth = itemWidth - tabItem.BorderThickness.Left;
tabItem.CurrentIndex = index;
tabItem.TargetOffsetX = 0;
ItemDic[index] = tabItem;
size.Width += tabItem.ItemWidth;
}
}
size.Height = constraint.Height;
_oldSize = size;
return _oldSize;
}
public TabPanel()
{
Loaded += (s, e) =>
{
if (_isLoaded) return;
ForceUpdate = true;
Measure(new Size(DesiredSize.Width, ActualHeight));
ForceUpdate = false;
foreach (var item in ItemDic.Values)
{
item.TabPanel = this;
}
_isLoaded = true;
};
}
}
}

View File

@@ -0,0 +1,619 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Media;
namespace AIStudio.Wpf.ADiagram.Controls
{
/// <summary>
/// A ruler control which supports both centimeters and inches. In order to use it vertically, change the <see cref="Marks">Marks</see> property to <c>Up</c> and rotate it ninety degrees.
/// </summary>
/// <remarks>
/// Contributions from <see
/// cref="http://www.orbifold.net/default/?p=2295&amp;cpage=1#comment-61500">Raf
/// Lenfers</see>
/// </remarks>
public class Ruler : FrameworkElement
{
#region Fields
private double SegmentHeight;
private readonly Pen p = new Pen(Brushes.Black, 1.0);
private readonly Pen ThinPen = new Pen(Brushes.Black, 0.5);
private readonly Pen BorderPen = new Pen(Brushes.Gray, 1.0);
private readonly Pen RedPen = new Pen(Brushes.Red, 2.0);
#endregion
#region Properties
#region Background
public Brush Background
{
get
{
return (Brush)GetValue(BackgroundProperty);
}
set
{
SetValue(BackgroundProperty, value);
}
}
/// <summary>
/// Identifies the Length dependency property.
/// </summary>
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register(
"Background",
typeof(Brush),
typeof(Ruler),
new FrameworkPropertyMetadata(new SolidColorBrush(Colors.White), FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
#region Length
/// <summary>
/// Gets or sets the length of the ruler. If the <see cref="AutoSize"/> property is set to false (default) this
/// is a fixed length. Otherwise the length is calculated based on the actual width of the ruler.
/// </summary>
public double Length
{
get
{
if (this.AutoSize)
{
return (double)(Unit == Unit.Cm ? DipHelper.DipToCm(this.ActualWidth) : DipHelper.DipToInch(this.ActualWidth)) / this.Zoom;
}
else
{
return (double)GetValue(LengthProperty);
}
}
set
{
SetValue(LengthProperty, value);
}
}
/// <summary>
/// Identifies the Length dependency property.
/// </summary>
public static readonly DependencyProperty LengthProperty =
DependencyProperty.Register(
"Length",
typeof(double),
typeof(Ruler),
new FrameworkPropertyMetadata(20D, FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
#region AutoSize
/// <summary>
/// Gets or sets the AutoSize behavior of the ruler.
/// false (default): the lenght of the ruler results from the <see cref="Length"/> property. If the window size is changed, e.g. wider
/// than the rulers length, free space is shown at the end of the ruler. No rescaling is done.
/// true : the length of the ruler is always adjusted to its actual width. This ensures that the ruler is shown
/// for the actual width of the window.
/// </summary>
public bool AutoSize
{
get
{
return (bool)GetValue(AutoSizeProperty);
}
set
{
SetValue(AutoSizeProperty, value);
this.InvalidateVisual();
}
}
/// <summary>
/// Identifies the AutoSize dependency property.
/// </summary>
public static readonly DependencyProperty AutoSizeProperty =
DependencyProperty.Register(
"AutoSize",
typeof(bool),
typeof(Ruler),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
#region Zoom
/// <summary>
/// Gets or sets the zoom factor for the ruler. The default value is 1.0.
/// </summary>
public double Zoom
{
get
{
return (double)GetValue(ZoomProperty);
}
set
{
SetValue(ZoomProperty, value);
this.InvalidateVisual();
}
}
/// <summary>
/// Identifies the Zoom dependency property.
/// </summary>
public static readonly DependencyProperty ZoomProperty =
DependencyProperty.Register("Zoom", typeof(double), typeof(Ruler),
new FrameworkPropertyMetadata((double)1.0,
FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
#region Chip
/// <summary>
/// Chip Dependency Property
/// </summary>
public static readonly DependencyProperty ChipProperty =
DependencyProperty.Register("Chip", typeof(double), typeof(Ruler),
new FrameworkPropertyMetadata((double)-1000,
FrameworkPropertyMetadataOptions.AffectsRender));
/// <summary>
/// Sets the location of the chip in the units of the ruler.
/// So, to set the chip to 10 in cm units the chip needs to be set to 10.
/// Use the <see cref="DipHelper"/> class for conversions.
/// </summary>
public double Chip
{
get { return (double)GetValue(ChipProperty); }
set { SetValue(ChipProperty, value); }
}
#endregion
#region CountShift
/// <summary>
/// CountShift Dependency Property
/// </summary>
public static readonly DependencyProperty CountShiftProperty =
DependencyProperty.Register("CountShift", typeof(double), typeof(Ruler),
new FrameworkPropertyMetadata(0d,
FrameworkPropertyMetadataOptions.AffectsRender));
/// <summary>
/// By default the counting of inches or cm starts at zero, this property allows you to shift
/// the counting.
/// </summary>
public double CountShift
{
get { return (double)GetValue(CountShiftProperty); }
set { SetValue(CountShiftProperty, value); }
}
#endregion
#region Marks
/// <summary>
/// Marks Dependency Property
/// </summary>
public static readonly DependencyProperty MarksProperty =
DependencyProperty.Register("Marks", typeof(MarksLocation), typeof(Ruler),
new FrameworkPropertyMetadata(MarksLocation.Up,
FrameworkPropertyMetadataOptions.AffectsRender));
/// <summary>
/// Gets or sets where the marks are shown in the ruler.
/// </summary>
public MarksLocation Marks
{
get { return (MarksLocation)GetValue(MarksProperty); }
set { SetValue(MarksProperty, value); }
}
#endregion
#region Unit
/// <summary>
/// Gets or sets the unit of the ruler.
/// Default value is Unit.Cm.
/// </summary>
public Unit Unit
{
get { return (Unit)GetValue(UnitProperty); }
set { SetValue(UnitProperty, value); }
}
/// <summary>
/// Identifies the Unit dependency property.
/// </summary>
public static readonly DependencyProperty UnitProperty =
DependencyProperty.Register(
"Unit",
typeof(Unit),
typeof(Ruler),
new FrameworkPropertyMetadata(Unit.Cm, FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
#endregion
#region Constructor
static Ruler()
{
HeightProperty.OverrideMetadata(typeof(Ruler), new FrameworkPropertyMetadata(20.0));
}
public Ruler()
{
SegmentHeight = this.Height - 10;
}
#endregion
#region Methods
/// <summary>
/// Participates in rendering operations.
/// </summary>
/// <param name="drawingContext">The drawing instructions for a specific element. This context is provided to the layout system.</param>
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var rect = new Rect(0, 0, RenderSize.Width, RenderSize.Height);
drawingContext.DrawRectangle(Background, null, rect);
double xDest = (Unit == Unit.Cm ? DipHelper.CmToDip(Length) : DipHelper.InchToDip(Length)) * this.Zoom;
drawingContext.DrawRectangle(null, BorderPen, new Rect(new Point(0.0, 0.0), new Point(xDest, Height)));
double chip = Unit == Unit.Cm ? DipHelper.CmToDip(Chip) : DipHelper.InchToDip(Chip);
drawingContext.DrawLine(RedPen, new Point(chip, 0), new Point(chip, Height));
//画偏移位置之前的
if (CountShift < 0)
{
for (double dUnit = -CountShift; dUnit > -1; dUnit--)
{
double d;
if (Unit == Unit.Cm)
{
d = DipHelper.CmToDip(dUnit) * this.Zoom;
if (dUnit < Length)
{
for (int i = 1; i <= 9; i++)
{
if (i != 5)
{
double dMm = DipHelper.CmToDip(dUnit + 0.1 * i) * this.Zoom;
if (Marks == MarksLocation.Up)
drawingContext.DrawLine(ThinPen, new Point(dMm, 0), new Point(dMm, SegmentHeight / 3.0));
else
drawingContext.DrawLine(ThinPen, new Point(dMm, Height), new Point(dMm, Height - SegmentHeight / 3.0));
}
}
double dMiddle = DipHelper.CmToDip(dUnit + 0.5) * this.Zoom;
if (Marks == MarksLocation.Up)
drawingContext.DrawLine(p, new Point(dMiddle, 0), new Point(dMiddle, SegmentHeight * 2.0 / 3.0));
else
drawingContext.DrawLine(p, new Point(dMiddle, Height), new Point(dMiddle, Height - SegmentHeight * 2.0 / 3.0));
}
}
else
{
d = DipHelper.InchToDip(dUnit) * this.Zoom;
if (dUnit < Length)
{
if (Marks == MarksLocation.Up)
{
double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;
drawingContext.DrawLine(ThinPen, new Point(dQuarter, 0),
new Point(dQuarter, SegmentHeight / 3.0));
double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;
drawingContext.DrawLine(p, new Point(dMiddle, 0),
new Point(dMiddle, SegmentHeight * 2D / 3D));
double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;
drawingContext.DrawLine(ThinPen, new Point(d3Quarter, 0),
new Point(d3Quarter, SegmentHeight / 3.0));
}
else
{
double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;
drawingContext.DrawLine(ThinPen, new Point(dQuarter, Height),
new Point(dQuarter, Height - SegmentHeight / 3.0));
double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;
drawingContext.DrawLine(p, new Point(dMiddle, Height),
new Point(dMiddle, Height - SegmentHeight * 2D / 3D));
double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;
drawingContext.DrawLine(ThinPen, new Point(d3Quarter, Height),
new Point(d3Quarter, Height - SegmentHeight / 3.0));
}
}
}
if (Marks == MarksLocation.Up)
drawingContext.DrawLine(p, new Point(d, 0), new Point(d, SegmentHeight));
else
drawingContext.DrawLine(p, new Point(d, Height), new Point(d, Height - SegmentHeight));
if ((dUnit != 0.0) && (dUnit < Length))
{
FormattedText ft = new FormattedText(
(dUnit + CountShift).ToString(CultureInfo.CurrentCulture),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Arial"),
DipHelper.PtToDip(6),
Brushes.DimGray);
ft.SetFontWeight(FontWeights.Regular);
ft.TextAlignment = TextAlignment.Center;
if (Marks == MarksLocation.Up)
drawingContext.DrawText(ft, new Point(d, Height - ft.Height));
else
drawingContext.DrawText(ft, new Point(d, Height - SegmentHeight - ft.Height));
}
}
}
//画偏移位置之后的
for (double dUnit = -CountShift; dUnit <= Length; dUnit++)
{
double d;
if (Unit == Unit.Cm)
{
d = DipHelper.CmToDip(dUnit) * this.Zoom;
if (dUnit < Length)
{
for (int i = 1; i <= 9; i++)
{
if (i != 5)
{
double dMm = DipHelper.CmToDip(dUnit + 0.1 * i) * this.Zoom;
if (Marks == MarksLocation.Up)
drawingContext.DrawLine(ThinPen, new Point(dMm, 0), new Point(dMm, SegmentHeight / 3.0));
else
drawingContext.DrawLine(ThinPen, new Point(dMm, Height), new Point(dMm, Height - SegmentHeight / 3.0));
}
}
double dMiddle = DipHelper.CmToDip(dUnit + 0.5) * this.Zoom;
if (Marks == MarksLocation.Up)
drawingContext.DrawLine(p, new Point(dMiddle, 0), new Point(dMiddle, SegmentHeight * 2.0 / 3.0));
else
drawingContext.DrawLine(p, new Point(dMiddle, Height), new Point(dMiddle, Height - SegmentHeight * 2.0 / 3.0));
}
}
else
{
d = DipHelper.InchToDip(dUnit) * this.Zoom;
if (dUnit < Length)
{
if (Marks == MarksLocation.Up)
{
double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;
drawingContext.DrawLine(ThinPen, new Point(dQuarter, 0),
new Point(dQuarter, SegmentHeight / 3.0));
double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;
drawingContext.DrawLine(p, new Point(dMiddle, 0),
new Point(dMiddle, SegmentHeight * 2D / 3D));
double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;
drawingContext.DrawLine(ThinPen, new Point(d3Quarter, 0),
new Point(d3Quarter, SegmentHeight / 3.0));
}
else
{
double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;
drawingContext.DrawLine(ThinPen, new Point(dQuarter, Height),
new Point(dQuarter, Height - SegmentHeight / 3.0));
double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;
drawingContext.DrawLine(p, new Point(dMiddle, Height),
new Point(dMiddle, Height - SegmentHeight * 2D / 3D));
double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;
drawingContext.DrawLine(ThinPen, new Point(d3Quarter, Height),
new Point(d3Quarter, Height - SegmentHeight / 3.0));
}
}
}
if (Marks == MarksLocation.Up)
drawingContext.DrawLine(p, new Point(d, 0), new Point(d, SegmentHeight));
else
drawingContext.DrawLine(p, new Point(d, Height), new Point(d, Height - SegmentHeight));
if ((dUnit != 0.0) && (dUnit < Length))
{
FormattedText ft = new FormattedText(
(dUnit + CountShift).ToString(CultureInfo.CurrentCulture),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Arial"),
DipHelper.PtToDip(6),
Brushes.DimGray);
ft.SetFontWeight(FontWeights.Regular);
ft.TextAlignment = TextAlignment.Center;
if (Marks == MarksLocation.Up)
drawingContext.DrawText(ft, new Point(d, Height - ft.Height));
else
drawingContext.DrawText(ft, new Point(d, Height - SegmentHeight - ft.Height));
}
}
}
/// <summary>
/// Measures an instance during the first layout pass prior to arranging it.
/// </summary>
/// <param name="availableSize">A maximum Size to not exceed.</param>
/// <returns>The maximum Size for the instance.</returns>
protected override Size MeasureOverride(Size availableSize)
{
return base.MeasureOverride(availableSize);
//Size desiredSize;
//if (Unit == Unit.Cm)
//{
// desiredSize = new Size(DipHelper.CmToDip(Length), Height);
//}
//else
//{
// desiredSize = new Size(DipHelper.InchToDip(Length), Height);
//}
//return desiredSize;
}
#endregion
}
/// <summary>
/// The unit type of the ruler.
/// </summary>
public enum Unit
{
/// <summary>
/// the unit is Centimeter.
/// </summary>
Cm,
/// <summary>
/// The unit is Inch.
/// </summary>
Inch
};
public enum MarksLocation
{
Up, Down
}
/// <summary>
/// A helper class for DIP (Device Independent Pixels) conversion and scaling operations.
/// </summary>
public static class DipHelper
{
/// <summary>
/// Converts millimeters to DIP (Device Independant Pixels).
/// </summary>
/// <param name="mm">A millimeter value.</param>
/// <returns>A DIP value.</returns>
public static double MmToDip(double mm)
{
return CmToDip(mm / 10.0);
}
/// <summary>
/// Converts centimeters to DIP (Device Independant Pixels).
/// </summary>
/// <param name="cm">A centimeter value.</param>
/// <returns>A DIP value.</returns>
public static double CmToDip(double cm)
{
return (cm * 96.0 / 2.54);
}
/// <summary>
/// Converts inches to DIP (Device Independant Pixels).
/// </summary>
/// <param name="inch">An inch value.</param>
/// <returns>A DIP value.</returns>
public static double InchToDip(double inch)
{
return (inch * 96.0);
}
public static double DipToInch(double dip)
{
return dip / 96D;
}
/// <summary>
/// Converts font points to DIP (Device Independant Pixels).
/// </summary>
/// <param name="pt">A font point value.</param>
/// <returns>A DIP value.</returns>
public static double PtToDip(double pt)
{
return (pt * 96.0 / 72.0);
}
/// <summary>
/// Converts DIP (Device Independant Pixels) to centimeters.
/// </summary>
/// <param name="dip">A DIP value.</param>
/// <returns>A centimeter value.</returns>
public static double DipToCm(double dip)
{
return (dip * 2.54 / 96.0);
}
/// <summary>
/// Converts DIP (Device Independant Pixels) to millimeters.
/// </summary>
/// <param name="dip">A DIP value.</param>
/// <returns>A millimeter value.</returns>
public static double DipToMm(double dip)
{
return DipToCm(dip) * 10.0;
}
/// <summary>
/// Gets the system DPI scale factor (compared to 96 dpi).
/// From http://blogs.msdn.com/jaimer/archive/2007/03/07/getting-system-dpi-in-wpf-app.aspx
/// Should not be called before the Loaded event (else XamlException mat throw)
/// </summary>
/// <returns>A Point object containing the X- and Y- scale factor.</returns>
private static Point GetSystemDpiFactor()
{
PresentationSource source = PresentationSource.FromVisual(Application.Current.MainWindow);
Matrix m = source.CompositionTarget.TransformToDevice;
return new Point(m.M11, m.M22);
}
private const double DpiBase = 96.0;
/// <summary>
/// Gets the system configured DPI.
/// </summary>
/// <returns>A Point object containing the X- and Y- DPI.</returns>
public static Point GetSystemDpi()
{
Point sysDpiFactor = GetSystemDpiFactor();
return new Point(
sysDpiFactor.X * DpiBase,
sysDpiFactor.Y * DpiBase);
}
/// <summary>
/// Gets the physical pixel density (DPI) of the screen.
/// </summary>
/// <param name="diagonalScreenSize">Size - in inch - of the diagonal of the screen.</param>
/// <returns>A Point object containing the X- and Y- DPI.</returns>
public static Point GetPhysicalDpi(double diagonalScreenSize)
{
Point sysDpiFactor = GetSystemDpiFactor();
double pixelScreenWidth = SystemParameters.PrimaryScreenWidth * sysDpiFactor.X;
double pixelScreenHeight = SystemParameters.PrimaryScreenHeight * sysDpiFactor.Y;
double formatRate = pixelScreenWidth / pixelScreenHeight;
double inchHeight = diagonalScreenSize / Math.Sqrt(formatRate * formatRate + 1.0);
double inchWidth = formatRate * inchHeight;
double xDpi = Math.Round(pixelScreenWidth / inchWidth);
double yDpi = Math.Round(pixelScreenHeight / inchHeight);
return new Point(xDpi, yDpi);
}
/// <summary>
/// Converts a DPI into a scale factor (compared to system DPI).
/// </summary>
/// <param name="dpi">A Point object containing the X- and Y- DPI to convert.</param>
/// <returns>A Point object containing the X- and Y- scale factor.</returns>
public static Point DpiToScaleFactor(Point dpi)
{
Point sysDpi = GetSystemDpi();
return new Point(
dpi.X / sysDpi.X,
dpi.Y / sysDpi.Y);
}
/// <summary>
/// Gets the scale factor to apply to a WPF application
/// so that 96 DIP always equals 1 inch on the screen (whatever the system DPI).
/// </summary>
/// <param name="diagonalScreenSize">Size - in inch - of the diagonal of the screen</param>
/// <returns>A Point object containing the X- and Y- scale factor.</returns>
public static Point GetScreenIndependentScaleFactor(double diagonalScreenSize)
{
return DpiToScaleFactor(GetPhysicalDpi(diagonalScreenSize));
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class BoolVisibilityConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var visibility = value as bool?;
var visible = parameter as string;
if (visibility != null && visible != null)
{
if (visibility == true && visible == "true")
{
return Visibility.Visible;
}
if (visibility == false && visible == "false")
{
return Visibility.Visible;
}
}
else if (visibility != null)
{
if (visibility == true)
{
return Visibility.Visible;
}
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
#endregion
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class Boolean2VisibilityReConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null && (bool)value ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,81 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class ConverterBoolToValueMap : MarkupExtension, IValueConverter
{
public override object ProvideValue(System.IServiceProvider serviceProvider)
{
return new ConverterBoolToValueMap
{
FromType = this.FromType ?? typeof(char),
TargetType = this.TargetType ?? typeof(bool),
Parameter = this.Parameter
};
}
public object Parameter
{
get;
set;
}
public Type TargetType
{
get;
set;
}
public Type FromType
{
get;
set;
}
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var result = DependencyProperty.UnsetValue;
if (value == null) return result;
if (value is bool)
{
if ((bool)value)
result = parameter;
else
result = this.Parameter;
if (result == null || string.IsNullOrWhiteSpace(result.ToString()))
return DependencyProperty.UnsetValue;
//处理枚举类型
if (targetType.IsEnum)
result = Enum.Parse(targetType, result as string);
else if (targetType.IsValueType)
{
if (targetType == typeof(Int32))
result = System.Convert.ToInt32(result);
else if (targetType == typeof(Int16))
result = System.Convert.ToInt16(result);
else if (targetType == typeof(char))
result = result.ToString().First();
}
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
return false;
if (object.Equals(value, parameter))
return true;
return string.Equals(value.ToString(), parameter.ToString());
}
#endregion
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class ConverterValueMapSetToVisibility : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
return DependencyProperty.UnsetValue;
IEnumerable<string> checkList = parameter.ToString().Split('^');
bool equal = checkList.Contains(value.ToString());
if (equal)
return Visibility.Visible;
else
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(System.IServiceProvider serviceProvider)
{
return new ConverterValueMapSetToVisibility
{
FromType = this.FromType ?? typeof(char),
TargetType = this.TargetType ?? typeof(bool),
Parameter = this.Parameter
};
}
public object Parameter
{
get;
set;
}
public Type TargetType
{
get;
set;
}
public Type FromType
{
get;
set;
}
}
}

View File

@@ -0,0 +1,81 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class ConverterValueMapToBool : MarkupExtension, IValueConverter
{
public override object ProvideValue(System.IServiceProvider serviceProvider)
{
return new ConverterValueMapToBool
{
FromType = this.FromType ?? typeof(char),
TargetType = this.TargetType ?? typeof(bool),
Parameter = this.Parameter
};
}
public object Parameter
{
get;
set;
}
public Type TargetType
{
get;
set;
}
public Type FromType
{
get;
set;
}
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
return false;
if (object.Equals(value, parameter))
return true;
return string.Equals(value.ToString(), parameter.ToString());
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var result = DependencyProperty.UnsetValue;
if (value == null) return result;
if (value is bool)
{
if ((bool)value)
result = parameter;
else
result = this.Parameter;
if (result == null || string.IsNullOrWhiteSpace(result.ToString()))
return DependencyProperty.UnsetValue;
//处理枚举类型
if (targetType.IsEnum)
result = Enum.Parse(targetType, result as string);
else if (targetType.IsValueType)
{
if (targetType == typeof(Int32))
result = System.Convert.ToInt32(result);
else if (targetType == typeof(Int16))
result = System.Convert.ToInt16(result);
else if (targetType == typeof(char))
result = result.ToString().First();
}
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class ConverterValueMapToVisibility : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
return DependencyProperty.UnsetValue;
bool equal = string.Equals(value.ToString(), parameter.ToString());
//true = Visible
if (equal)
return Visibility.Visible;
else
return this.Parameter != null && this.Parameter.ToString().ToLower() == Visibility.Hidden.ToString().ToLower() ? Visibility.Hidden : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(System.IServiceProvider serviceProvider)
{
return new ConverterValueMapToVisibility
{
FromType = this.FromType ?? typeof(char),
TargetType = this.TargetType ?? typeof(bool),
Parameter = this.Parameter
};
}
public object Parameter
{
get;
set;
}
public Type TargetType
{
get;
set;
}
public Type FromType
{
get;
set;
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class ConverterValueSetToOppositeVisibility : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
return DependencyProperty.UnsetValue;
IEnumerable<string> checkList = parameter.ToString().Split('^');
bool equal = checkList.Contains(value.ToString());
if (equal)
return Visibility.Collapsed;
else
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(System.IServiceProvider serviceProvider)
{
return new ConverterValueSetToOppositeVisibility
{
FromType = this.FromType ?? typeof(char),
TargetType = this.TargetType ?? typeof(bool),
Parameter = this.Parameter
};
}
public object Parameter
{
get;
set;
}
public Type TargetType
{
get;
set;
}
public Type FromType
{
get;
set;
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using AIStudio.Wpf.ADiagram.Controls;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class CountShiftConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values != null && values.Length > 2)
{
var diagram = values[0] as Util.DiagramDesigner.DiagramControl;
var zoomValue = (double)values[1];
var pageunit = (PageUnit)values[2];
var unit = Unit.Cm;
if (pageunit > PageUnit.km)
{
unit = Unit.Inch;
}
Vector vector = System.Windows.Media.VisualTreeHelper.GetOffset(diagram);
if (parameter?.ToString() == "Y")
{
var value = 0 - (unit == Unit.Cm? DipHelper.DipToCm(vector.Y - 20) : DipHelper.DipToInch(vector.Y - 20))/ zoomValue;
return value;
}
else
{
var value = 0 - (unit == Unit.Cm ? DipHelper.DipToCm(vector.X - 20) : DipHelper.DipToInch(vector.X - 20)) / zoomValue;
return value;
}
}
return 0;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,85 @@
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class DoubleToThickness : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
if (parameter != null)
{
switch (parameter.ToString())
{
case "Left":
return new Thickness(System.Convert.ToDouble(value), 0, 0, 0);
case "Top":
return new Thickness(0, System.Convert.ToDouble(value), 0, 0);
case "Right":
return new Thickness(0, 0, System.Convert.ToDouble(value), 0);
case "Buttom":
return new Thickness(0, 0, 0, System.Convert.ToDouble(value));
case "LeftTop":
return new Thickness(System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0, 0);
case "LeftButtom":
return new Thickness(System.Convert.ToDouble(value), 0, 0, System.Convert.ToDouble(value));
case "RightTop":
return new Thickness(0, System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0);
case "RigthButtom":
return new Thickness(0, 0, System.Convert.ToDouble(value), System.Convert.ToDouble(value));
case "LeftRight":
return new Thickness(System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value), 0);
case "TopButtom":
return new Thickness(0, System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value));
default:
return new Thickness(System.Convert.ToDouble(value));
}
}
return new Thickness(System.Convert.ToDouble(value));
}
return new Thickness(0);
}
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
if (parameter != null)
{
switch (parameter.ToString())
{
case "Left":
return ((Thickness)value).Left;
case "Top":
return ((Thickness)value).Top;
case "Right":
return ((Thickness)value).Right;
case "Buttom":
return ((Thickness)value).Bottom;
default:
return ((Thickness)value).Left;
}
}
return ((Thickness)value).Left;
}
return 0.0;
}
}
}

View File

@@ -0,0 +1,50 @@
/**************************************************************************************
Toolkit for WPF
Copyright (C) 2007-2016 Xceed Software Inc.
This program is provided to you under the terms of the Microsoft Public
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
For more features, controls, and fast professional support,
pick up the Plus Edition at https://xceed.com/xceed-toolkit-plus-for-wpf/
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
************************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows.Media;
namespace AIStudio.Wpf.ADiagram.Converters
{
class HtmlColorConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((value != null) && value is System.Windows.Media.Color)
return new SolidColorBrush((System.Windows.Media.Color)value);
if ((value != null) && value is string str)
{
BrushConverter brushConverter = new BrushConverter();
return (Brush)brushConverter.ConvertFromString(str);
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@@ -0,0 +1,39 @@
using System.Windows.Data;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class IndentConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double colunwidth = 10;
double left = 0.0;
UIElement element = value as TreeViewItem;
while (element.GetType() != typeof(TreeView))
{
element = (UIElement)VisualTreeHelper.GetParent(element);
if (element.GetType() == typeof(TreeViewItem))
left += colunwidth;
}
return new Thickness(left, 0, 0, 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace AIStudio.Wpf.ADiagram.Converters
{
//选中项索引转换成可见项
public class IntVisibilityConverter : MarkupExtension, IValueConverter
{
/// <summary>
/// Returns the value for the target property of this markup extension.
/// </summary>
/// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
/// <returns>Reference to the instance of this Int32IndexToNumberConverter.</returns>
public override object ProvideValue(System.IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is int && parameter is string) //与参数相同则显示
{
if (parameter.ToString().Contains("^"))
{
var paras = parameter.ToString().Split('^');
foreach(var para in paras)
{
if (value.ToString() == para)
{
return Visibility.Visible;
}
}
return Visibility.Collapsed;
}
else
{
if (value.ToString() == (string)parameter)
{
return Visibility.Visible;
}
}
}
else if (value is int) //无参数则大于0显示
{
if ((int)value > 0)
{
return Visibility.Visible;
}
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class NullableToBooleanConverter : IValueConverter
{
public bool NullValue { get; set; } = false;
public bool NotNullValue { get; set; } = true;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? NullValue : NotNullValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class NullableToVisibilityConverter : IValueConverter
{
public Visibility NullValue { get; set; } = Visibility.Collapsed;
public Visibility NotNullValue { get; set; } = Visibility.Visible;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? NullValue : NotNullValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class NumberConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return 0.ToString("00");
return (System.Convert.ToInt32(value) + 1).ToString("00");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,36 @@
using AIStudio.Wpf.ADiagram.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class RulerUnitConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is PageUnit pageunit)
{
if (pageunit > PageUnit.km)
{
return Unit.Inch;
}
else
{
return Unit.Cm;
}
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class StringPathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string)
{
Geometry geo = Geometry.Parse(value as string);
return geo;
//GeometryConverter gc = new GeometryConverter();
//return (Geometry)gc.ConvertFromString(value as string);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace AIStudio.Wpf.ADiagram.Converters
{
/// <summary>
/// Converts a Thickness to a new Thickness. It's possible to ignore a side With the IgnoreThicknessSide property.
/// </summary>
public class ThicknessBindingConverter : IValueConverter
{
public IgnoreThicknessSideType IgnoreThicknessSide { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Thickness)
{
// yes, we can override it with the parameter value
if (parameter is IgnoreThicknessSideType)
{
this.IgnoreThicknessSide = (IgnoreThicknessSideType)parameter;
}
var orgThickness = (Thickness)value;
switch (this.IgnoreThicknessSide)
{
case IgnoreThicknessSideType.Left:
return new Thickness(0, orgThickness.Top, orgThickness.Right, orgThickness.Bottom);
case IgnoreThicknessSideType.Top:
return new Thickness(orgThickness.Left, 0, orgThickness.Right, orgThickness.Bottom);
case IgnoreThicknessSideType.Right:
return new Thickness(orgThickness.Left, orgThickness.Top, 0, orgThickness.Bottom);
case IgnoreThicknessSideType.Bottom:
return new Thickness(orgThickness.Left, orgThickness.Top, orgThickness.Right, 0);
default:
return orgThickness;
}
}
return default(Thickness);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// for now no back converting
return DependencyProperty.UnsetValue;
}
}
public enum IgnoreThicknessSideType
{
/// <summary>
/// Use all sides.
/// </summary>
None,
/// <summary>
/// Ignore the left side.
/// </summary>
Left,
/// <summary>
/// Ignore the top side.
/// </summary>
Top,
/// <summary>
/// Ignore the right side.
/// </summary>
Right,
/// <summary>
/// Ignore the bottom side.
/// </summary>
Bottom
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace AIStudio.Wpf.ADiagram.Converters
{
public class ThicknessToDoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((Thickness)value).Left;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
internal class DoubleToRightMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return new Thickness(0, 0, ((double)value), 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
internal class DoubleToLeftMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return new Thickness(((double)value), 0, 0, 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
internal class DoubleToLeftRightMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return new Thickness((double)value, 0, (double)value, 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
{
public static class FlowchartService
{
static FlowchartService()
{
Users = new List<SelectOption>()
{
new SelectOption(){ value = "操作员1",text = "操作员1" },
new SelectOption(){ value = "操作员2",text = "操作员2" },
new SelectOption(){ value = "Admin",text = "Admin" },
};
Roles = new List<SelectOption>()
{
new SelectOption(){ value = "操作员",text = "操作员" },
new SelectOption(){ value = "管理员",text = "管理员" },
};
}
private static List<SelectOption> _users;
public static List<SelectOption> Users
{
get { return _users; }
set
{
_users = value;
}
}
private static List<SelectOption> _roles;
public static List<SelectOption> Roles
{
get { return _roles; }
set
{
_roles = value;
}
}
}
}

View File

@@ -0,0 +1,102 @@
using AIStudio.Wpf.ADiagram.ViewModels;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
{
public class FlowchartViewModel : DiagramsViewModel
{
public FlowchartViewModel(MainWindowViewModel mainWindowViewModel, string title, string status, DiagramType diagramType) : base(mainWindowViewModel, title, status, diagramType)
{
}
public FlowchartViewModel(MainWindowViewModel mainWindowViewModel, string filename) : base(mainWindowViewModel, filename)
{
}
protected override void InitDiagramViewModel()
{
base.InitDiagramViewModel();
DiagramViewModel.ShowGrid = true;
DiagramViewModel.GridCellSize = new Size(100, 100);
DiagramViewModel.CellHorizontalAlignment = CellHorizontalAlignment.Center;
DiagramViewModel.CellVerticalAlignment = CellVerticalAlignment.Center;
}
protected override void Init()
{
base.Init();
DesignerItemViewModelBase start = new StartFlowNode() { Left = 100, Top = 0, Color = Colors.Green.ToString() };
DiagramViewModel.DirectAddItemCommand.Execute(start);
DesignerItemViewModelBase middle1 = new MiddleFlowNode() { Left = 100, Top = 100, Color = Colors.Yellow.ToString(), Text = "主管审批" };
DiagramViewModel.DirectAddItemCommand.Execute(middle1);
DesignerItemViewModelBase decide = new DecideFlowNode() { Left = 100, Top = 200, Color = Colors.Yellow.ToString(), Text = "条件" };
DiagramViewModel.DirectAddItemCommand.Execute(decide);
DesignerItemViewModelBase middle2 = new MiddleFlowNode() { Left = 200, Top = 300, Color = Colors.Yellow.ToString(), Text = "分管领导" };
DiagramViewModel.DirectAddItemCommand.Execute(middle2);
DesignerItemViewModelBase cobegin = new COBeginFlowNode() { Left = 100, Top = 400, Color = Colors.Yellow.ToString() };
DiagramViewModel.DirectAddItemCommand.Execute(cobegin);
DesignerItemViewModelBase middle3 = new MiddleFlowNode() { Left = 100, Top = 500, Color = Colors.Yellow.ToString(), Text = "财务审批" };
DiagramViewModel.DirectAddItemCommand.Execute(middle3);
DesignerItemViewModelBase middle4 = new MiddleFlowNode() { Left = 200, Top = 500, Color = Colors.Yellow.ToString(), Text = "人力审批" };
DiagramViewModel.DirectAddItemCommand.Execute(middle4);
DesignerItemViewModelBase coend = new COEndFlowNode() { Left = 100, Top = 600, Color = Colors.Yellow.ToString() };
DiagramViewModel.DirectAddItemCommand.Execute(coend);
DesignerItemViewModelBase end = new EndFlowNode() { Left = 100, Top = 700, Color = Colors.Yellow.ToString() };
DiagramViewModel.DirectAddItemCommand.Execute(end);
ConnectorViewModel connector1 = new ConnectorViewModel(start.BottomConnector, middle1.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector1);
ConnectorViewModel connector2 = new ConnectorViewModel(middle1.BottomConnector, decide.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector2);
ConnectorViewModel connector3 = new ConnectorViewModel(decide.RightConnector, middle2.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector3);
connector3.AddText(">=3");
ConnectorViewModel connector4 = new ConnectorViewModel(middle2.BottomConnector, cobegin.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector4);
ConnectorViewModel connector5 = new ConnectorViewModel(decide.BottomConnector, cobegin.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector5);
connector5.AddText("<3");
ConnectorViewModel connector6 = new ConnectorViewModel(cobegin.BottomConnector, middle3.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector6);
ConnectorViewModel connector7 = new ConnectorViewModel(cobegin.BottomConnector, middle4.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector7);
ConnectorViewModel connector8 = new ConnectorViewModel(middle3.BottomConnector, coend.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector8);
ConnectorViewModel connector9 = new ConnectorViewModel(middle4.BottomConnector, coend.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector9);
ConnectorViewModel connector10 = new ConnectorViewModel(coend.BottomConnector, end.TopConnector);
DiagramViewModel.DirectAddItemCommand.Execute(connector10);
DiagramViewModel.ClearSelectedItems();
}
}
}

View File

@@ -0,0 +1,50 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Xml.Serialization;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
{
public class FlowNodeDesignerItem : DesignerItemBase
{
public FlowNodeDesignerItem()
{
}
public FlowNodeDesignerItem(FlowNode item) : base(item)
{
if (item is MiddleFlowNode middleFlow)
{
UserIds = middleFlow.UserIds;
RoleIds = middleFlow.RoleIds;
ActType = middleFlow.ActType;
}
Color = item.Color;
Kind = item.Kind;
StateImage = item.StateImage;
}
[XmlArray]
public List<string> UserIds { get; set; }
[XmlArray]
public List<string> RoleIds { get; set; }
[XmlAttribute]
public string ActType { get; set; }
[XmlAttribute]
public string Color { get; set; }
[XmlAttribute]
public NodeKinds Kind { get; set; }
[XmlAttribute]
public string StateImage { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
{
public enum NodeKinds
{
[Description("节点")]
Normal = 0,
[Description("开始")]
Start = 1,
[Description("结束")]
End = 2,
[Description("中间节点")]
Middle = 3,
[Description("条件节点")]
Decide = 4,
[Description("并行开始")]
COBegin = 5,
[Description("并行结束")]
COEnd = 6,
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
{
/// <summary>
/// 前端SelectOption
/// </summary>
public class SelectOption
{
public string value { get; set; }
public string text { get; set; }
public override string ToString()
{
return text;
}
}
}

View File

@@ -0,0 +1,136 @@
using AIStudio.Wpf.ADiagram.Helpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
{
public class FlowNode : DesignerItemViewModelBase
{
public FlowNode(NodeKinds kind) : base()
{
Kind = kind;
Text = Kind.GetDescription();
ShowText = true;
ItemWidth = 80;
ItemHeight = 40;
}
public FlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
protected override void Init()
{
base.Init();
ShowRotate = false;
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
FlowNodeDesignerItem designer = designerbase as FlowNodeDesignerItem;
this.Color = designer.Color;
this.Kind = designer.Kind;
this.StateImage = designer.StateImage;
if (this is MiddleFlowNode middle)
{
middle.UserIds = designer.UserIds;
middle.RoleIds = designer.RoleIds;
middle.ActType = designer.ActType;
}
}
private string _color;
[Browsable(true)]
public string Color
{
get { return _color; }
set
{
SetProperty(ref _color, value);
}
}
[Browsable(false)]
public NodeKinds Kind { get; set; }
[Browsable(false)]
public string StateImage { get; set; }
}
public class StartFlowNode : FlowNode
{
public StartFlowNode() : base(NodeKinds.Start)
{
}
public StartFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
}
public class EndFlowNode : FlowNode
{
public EndFlowNode() : base(NodeKinds.End)
{
}
public EndFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
}
public class DecideFlowNode : FlowNode
{
public DecideFlowNode() : base(NodeKinds.Decide)
{
}
public DecideFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
}
public class COBeginFlowNode : FlowNode
{
public COBeginFlowNode() : base(NodeKinds.COBegin)
{
}
public COBeginFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
}
public class COEndFlowNode : FlowNode
{
public COEndFlowNode() : base(NodeKinds.COEnd)
{
}
public COEndFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
}
}

View File

@@ -0,0 +1,129 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Models"
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
xmlns:demo="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Flowchart"
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters">
<converter:HtmlColorConverter x:Key="HtmlColorConverter"/>
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
<ControlTemplate x:Key="NormalNodeStyle" TargetType="{x:Type ContentControl}">
<Grid>
<Border BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
<Grid>
<Border HorizontalAlignment="Left" Width="3" Background="{Binding Color}"/>
</Grid>
</Border>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="StartNodeStyle" TargetType="{x:Type ContentControl}">
<Grid>
<Border CornerRadius="3" BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
<Grid>
<Border HorizontalAlignment="Left" CornerRadius="3,0,0,3" Width="3" Background="{Binding Color}"/>
</Grid>
</Border>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="EndNodeStyle" TargetType="{x:Type ContentControl}">
<Grid>
<Border CornerRadius="3" BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
<Grid>
<Border HorizontalAlignment="Left" CornerRadius="3,0,0,3" Width="3" Background="{Binding Color}"/>
</Grid>
</Border>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="MiddleNodeStyle" TargetType="{x:Type ContentControl}">
<Grid>
<Border BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
<Grid>
<Border HorizontalAlignment="Left" Width="3" Background="{Binding Color}"/>
</Grid>
</Border>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="DecideNodeStyle" TargetType="{x:Type ContentControl}">
<Grid>
<Path Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" StrokeThickness="1" Stretch="Fill" Data="M 0,0.25 L 0.5 0 L 1,0.25 L 0.5,0.5 Z"></Path>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="COBeginNodeStyle" TargetType="{x:Type ContentControl}">
<Grid>
<Border BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
<Grid>
<Border HorizontalAlignment="Left" Width="3" Background="{Binding Color}"/>
</Grid>
</Border>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="COEndNodeStyle" TargetType="{x:Type ContentControl}">
<Grid>
<Border BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
<Grid>
<Border HorizontalAlignment="Left" Width="3" Background="{Binding Color}"/>
</Grid>
</Border>
</Grid>
</ControlTemplate>
<Style x:Key="CustomFlowNodeStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Template" Value="{StaticResource NormalNodeStyle}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Kind}" Value="Start">
<Setter Property="Template" Value="{StaticResource StartNodeStyle}" />
</DataTrigger>
<DataTrigger Binding="{Binding Kind}" Value="End">
<Setter Property="Template" Value="{StaticResource EndNodeStyle}" />
</DataTrigger>
<DataTrigger Binding="{Binding Kind}" Value="Middle">
<Setter Property="Template" Value="{StaticResource MiddleNodeStyle}" />
</DataTrigger>
<DataTrigger Binding="{Binding Kind}" Value="Decide">
<Setter Property="Template" Value="{StaticResource DecideNodeStyle}" />
</DataTrigger>
<DataTrigger Binding="{Binding Kind}" Value="COBegin">
<Setter Property="Template" Value="{StaticResource COBeginNodeStyle}" />
</DataTrigger>
<DataTrigger Binding="{Binding Kind}" Value="COEnd">
<Setter Property="Template" Value="{StaticResource COEndNodeStyle}" />
</DataTrigger>
</Style.Triggers>
</Style>
<DataTemplate DataType="{x:Type model:FlowchartToolBoxData}">
<Grid Width="{Binding Width}" Height="{Binding Height}">
<Rectangle Name="Border"
StrokeThickness="1"
StrokeDashArray="2"
Fill="Transparent"
SnapsToDevicePixels="true"/>
<Viewbox Stretch="Fill">
<Grid>
<ContentControl Style="{StaticResource CustomFlowNodeStyle}" Margin="2"/>
<TextBlock Text="{Binding Text}" Margin="5" Foreground="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</Viewbox>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Stroke" Value="Gray"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate DataType="{x:Type demo:FlowNode}">
<Grid IsHitTestVisible="False">
<ContentControl Style="{StaticResource CustomFlowNodeStyle}"/>
</Grid>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,60 @@
using AIStudio.Wpf.ADiagram.Controls;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
{
public class MiddleFlowNode : FlowNode
{
public MiddleFlowNode() : base(NodeKinds.Middle)
{
}
public MiddleFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
private List<string> _userIds = new List<string>();
[Browsable(true)]
[StyleName("UserIdsStyle")]
public List<string> UserIds
{
get { return _userIds; }
set
{
SetProperty(ref _userIds, value);
}
}
private List<string> _roleIds = new List<string>();
[Browsable(true)]
[StyleName("RoleIdsStyle")]
public List<string> RoleIds
{
get { return _roleIds; }
set
{
SetProperty(ref _roleIds, value);
}
}
private string _actType;
[Browsable(true)]
[StyleName("ActTypeStyle")]
public string ActType
{
get { return _actType; }
set
{
SetProperty(ref _actType, value);
}
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Logical
{
public class LinkPoint: BindableBase
{
public Guid Id { get; set; }
public string Name { get; set; }
private double _value;
public double Value
{
get { return _value; }
set
{
SetProperty(ref _value, value);
}
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Demos.Logical
{
public static class LogicalService
{
public static List<LinkPoint> LinkPoint { get; set; }
static LogicalService()
{
LinkPoint = new List<LinkPoint>();
for (int i = 0; i < 10; i++)
{
LinkPoint.Add(new Logical.LinkPoint { Id = Guid.NewGuid(), Name = $"测点{i}", Value = i });
}
}
}
}

View File

@@ -0,0 +1,416 @@
using AIStudio.Wpf.ADiagram.ViewModels;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Logical
{
public class LogicalViewModel : DiagramsViewModel
{
public LogicalViewModel(MainWindowViewModel mainWindowViewModel, string title, string status, DiagramType diagramType) : base(mainWindowViewModel, title, status, diagramType)
{
}
public LogicalViewModel(MainWindowViewModel mainWindowViewModel, string filename) : base(mainWindowViewModel, filename)
{
}
protected override void InitDiagramViewModel()
{
base.InitDiagramViewModel();
DiagramViewModel.ShowGrid = true;
DiagramViewModel.GridCellSize = new Size(150, 100);
DiagramViewModel.PageSizeOrientation = PageSizeOrientation.Horizontal;
DiagramViewModel.CellHorizontalAlignment = CellHorizontalAlignment.Left;
DiagramViewModel.CellVerticalAlignment = CellVerticalAlignment.None;
DiagramViewModel.Items.CollectionChanged += Items_CollectionChanged;
}
protected override void Init()
{
base.Init();
TimerDesignerItemViewModel timer = new TimerDesignerItemViewModel() { Left = 0, Top = 10 };
timer.Value = 0.5;
DiagramViewModel.DirectAddItemCommand.Execute(timer);
InputItemViewModel in1 = new InputItemViewModel() { Left = 0, Top = 50 };
in1.LinkPoint = LogicalService.LinkPoint[0];
DiagramViewModel.DirectAddItemCommand.Execute(in1);
InputItemViewModel in2 = new InputItemViewModel() { Left = 0, Top = 80 };
in2.LinkPoint = LogicalService.LinkPoint[1];
DiagramViewModel.DirectAddItemCommand.Execute(in2);
AddGateItemViewModel item1 = new AddGateItemViewModel() { Left = 150, Top = 50 };
DiagramViewModel.DirectAddItemCommand.Execute(item1);
ConstantDesignerItemViewModel constant = new ConstantDesignerItemViewModel() { Left = 150, Top = 118 };
DiagramViewModel.DirectAddItemCommand.Execute(constant);
GTGateItemViewModel gTGate = new GTGateItemViewModel() { Left = 300, Top = 50 };
DiagramViewModel.DirectAddItemCommand.Execute(gTGate);
InputItemViewModel in3 = new InputItemViewModel() { Left = 300, Top = 118 };
in3.LinkPoint = LogicalService.LinkPoint[2];
DiagramViewModel.DirectAddItemCommand.Execute(in3);
InputItemViewModel in4 = new InputItemViewModel() { Left = 300, Top = 148 };
in4.LinkPoint = LogicalService.LinkPoint[3];
DiagramViewModel.DirectAddItemCommand.Execute(in4);
SELGateItemViewModel sELGate = new SELGateItemViewModel() { Left = 450, Top = 50 };
DiagramViewModel.DirectAddItemCommand.Execute(sELGate);
OutputItemViewModel out1 = new OutputItemViewModel() { Left = 600, Top = 50 };
out1.LinkPoint = LogicalService.LinkPoint[4];
DiagramViewModel.DirectAddItemCommand.Execute(out1);
ConnectorViewModel connector1 = new ConnectorViewModel(in1.Output[0], item1.Input[0]);
DiagramViewModel.DirectAddItemCommand.Execute(connector1);
ConnectorViewModel connector2 = new ConnectorViewModel(in2.Output[0], item1.Input[1]);
DiagramViewModel.DirectAddItemCommand.Execute(connector2);
ConnectorViewModel connector3 = new ConnectorViewModel(item1.Output[0], gTGate.Input[0]);
DiagramViewModel.DirectAddItemCommand.Execute(connector3);
ConnectorViewModel connector4 = new ConnectorViewModel(constant.Output[0], gTGate.Input[1]);
DiagramViewModel.DirectAddItemCommand.Execute(connector4);
ConnectorViewModel connector5 = new ConnectorViewModel(gTGate.Output[0], sELGate.Input[0]);
DiagramViewModel.DirectAddItemCommand.Execute(connector5);
ConnectorViewModel connector6 = new ConnectorViewModel(in3.Output[0], sELGate.Input[1]);
DiagramViewModel.DirectAddItemCommand.Execute(connector6);
ConnectorViewModel connector7 = new ConnectorViewModel(in4.Output[0], sELGate.Input[2]);
DiagramViewModel.DirectAddItemCommand.Execute(connector7);
ConnectorViewModel connector8 = new ConnectorViewModel(sELGate.Output[0], out1.Input[0]);
DiagramViewModel.DirectAddItemCommand.Execute(connector8);
}
private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (var item in e.OldItems.OfType<TimerDesignerItemViewModel>())
{
item.Do -= Do;
}
}
if (e.NewItems != null)
{
foreach (var item in e.NewItems.OfType<TimerDesignerItemViewModel>())
{
item.Do += Do;
}
}
RaisePropertyChanged("Items");
}
protected override bool AddVerify(SelectableDesignerItemViewModelBase arg)
{
if (base.AddVerify(arg) == false)
return false;
if (arg is ConnectorViewModel connector)
{
if (connector.SinkConnectorInfo is FullyCreatedConnectorInfo fully)
{
if (DiagramViewModel.Items.OfType<ConnectorViewModel>().Any(p => p.SinkConnectorInfo == fully))
{
return false;
}
}
}
return true;
}
private void Do()
{
foreach (var item in DiagramViewModel.Items.OfType<ConstantDesignerItemViewModel>())
{
foreach (var output in item.Output)
{
output.Value.ConnectorValue = item.Value;
output.Value.ColorViewModel.FillColor.Color = Colors.Green;
}
}
foreach (var item in DiagramViewModel.Items.OfType<InputItemViewModel>())
{
if (item.LinkPoint != null)
{
foreach (var output in item.Output)
{
output.Value.ConnectorValue = item.LinkPoint.Value;
output.Value.ColorViewModel.FillColor.Color = Colors.Green;
}
}
}
foreach (var item in DiagramViewModel.Items.OfType<LogicalGateItemViewModelBase>().OrderBy(p => p.OrderNumber))
{
if (item.LogicalType != LogicalType.None)
{
foreach (var input in item.Input)
{
var connector = GetSourceItem(input.Value);
if (connector == null)
{
continue;
}
if (connector.SourceConnectorInfo.DataItem is LogicalGateItemViewModelBase)
{
input.Value.ConnectorValue = connector.SourceConnectorInfo.ConnectorValue;
input.Value.ColorViewModel.FillColor.Color = connector.SourceConnectorInfo.ColorViewModel.FillColor.Color;
connector.ColorViewModel.LineColor.Color = connector.SourceConnectorInfo.ColorViewModel.FillColor.Color;
if (item.LogicalType == LogicalType.Output)
{
input.Value.ValueTypePoint = connector.SourceConnectorInfo.ValueTypePoint;
}
else if (item.LogicalType == LogicalType.NOT)
{
input.Value.ValueTypePoint = (connector.SourceConnectorInfo.ValueTypePoint == ValueTypePoint.Bool) ? ValueTypePoint.Bool : ValueTypePoint.Int;
}
}
}
foreach (var output in item.Output)
{
if (item.LogicalType == LogicalType.Output)
{
var first = item.Input.Values.FirstOrDefault();
output.Value.ConnectorValue = first.ConnectorValue;
output.Value.ValueTypePoint = first.ValueTypePoint;
(item as OutputItemViewModel).Value = first.ConnectorValue;
(item as OutputItemViewModel).LinkPoint.Value = first.ConnectorValue;
}
else if (item.LogicalType == LogicalType.ADD)
{
output.Value.ConnectorValue = item.Input.Values.Select(p => p.ConnectorValue).Sum();
}
else if (item.LogicalType == LogicalType.SUB)
{
var first = item.Input.Values.Select(p => p.ConnectorValue).FirstOrDefault();
var second = item.Input.Values.Where((value, index) => index != 0).Select(p => p.ConnectorValue).Sum();
output.Value.ConnectorValue = first - second;
}
else if (item.LogicalType == LogicalType.MUL)
{
double result = 0;
foreach (var input in item.Input.Values)
{
if (result == 0)
{
result = 1;
}
result *= input.ConnectorValue;
}
output.Value.ConnectorValue = result;
}
else if (item.LogicalType == LogicalType.DIV)
{
double result = item.Input.Values.Select(p => p.ConnectorValue).FirstOrDefault();
foreach (var input in item.Input.Values.Where((value, index) => index != 0))
{
result /= input.ConnectorValue;
}
output.Value.ConnectorValue = result;
}
else if (item.LogicalType == LogicalType.AVE)
{
output.Value.ConnectorValue = item.Input.Values.Select(p => p.ConnectorValue).Average();
}
else if (item.LogicalType == LogicalType.MOD)
{
output.Value.ConnectorValue = item.Input[0].ConnectorValue % item.Input[1].ConnectorValue;
}
else if (item.LogicalType == LogicalType.AND)
{
output.Value.ConnectorValue = Convert.ToInt32(item.Input[0].ConnectorValue) & Convert.ToInt32(item.Input[1].ConnectorValue);
}
else if (item.LogicalType == LogicalType.OR)
{
output.Value.ConnectorValue = Convert.ToInt32(item.Input[0].ConnectorValue) | Convert.ToInt32(item.Input[1].ConnectorValue);
}
else if (item.LogicalType == LogicalType.XOR)
{
output.Value.ConnectorValue = Convert.ToInt32(Convert.ToInt32(item.Input[0].ConnectorValue) ^ Convert.ToInt32(item.Input[1].ConnectorValue));
}
else if (item.LogicalType == LogicalType.NOT)
{
if (item.Input[0].ValueTypePoint == ValueTypePoint.Bool)
{
output.Value.ConnectorValue = Convert.ToInt32(!Convert.ToBoolean(item.Input[0].ConnectorValue));
output.Value.ValueTypePoint = ValueTypePoint.Bool;
}
else
{
output.Value.ConnectorValue = ~Convert.ToInt32(item.Input[0].ConnectorValue);
output.Value.ValueTypePoint = ValueTypePoint.Int;
}
}
else if (item.LogicalType == LogicalType.SHL)
{
output.Value.ConnectorValue = Convert.ToInt32(item.Input[0].ConnectorValue) << Convert.ToInt32(item.Input[1].ConnectorValue);
}
else if (item.LogicalType == LogicalType.SHR)
{
output.Value.ConnectorValue = Convert.ToInt32(item.Input[0].ConnectorValue) >> Convert.ToInt32(item.Input[1].ConnectorValue);
}
else if (item.LogicalType == LogicalType.ROL)
{
output.Value.ConnectorValue = (Convert.ToInt32(item.Input[0].ConnectorValue) << Convert.ToInt32(item.Input[1].ConnectorValue)) | (Convert.ToInt32(item.Input[0].ConnectorValue) >> 32 - Convert.ToInt32(item.Input[1].ConnectorValue));
}
else if (item.LogicalType == LogicalType.ROR)
{
output.Value.ConnectorValue = (Convert.ToInt32(item.Input[0].ConnectorValue) >> Convert.ToInt32(item.Input[1].ConnectorValue)) | (Convert.ToInt32(item.Input[0].ConnectorValue) << 32 - Convert.ToInt32(item.Input[1].ConnectorValue));
}
else if (item.LogicalType == LogicalType.SEL)
{
output.Value.ConnectorValue = (item.Input[0].ConnectorValue == output.Key) ? item.Input[1].ConnectorValue : item.Input[2].ConnectorValue;
}
else if (item.LogicalType == LogicalType.MAX)
{
output.Value.ConnectorValue = item.Input.Values.Select(p => p.ConnectorValue).Max();
}
else if (item.LogicalType == LogicalType.MIN)
{
output.Value.ConnectorValue = item.Input.Values.Select(p => p.ConnectorValue).Min();
}
else if (item.LogicalType == LogicalType.LIMIT)
{
output.Value.ConnectorValue = (item.Input[0].ConnectorValue > item.Input[1].ConnectorValue) ? item.Input[1].ConnectorValue : item.Input[0].ConnectorValue;
}
else if (item.LogicalType == LogicalType.GT)
{
output.Value.ConnectorValue = (item.Input[0].ConnectorValue > item.Input[1].ConnectorValue) ? 1 : 0;
}
else if (item.LogicalType == LogicalType.LT)
{
output.Value.ConnectorValue = (item.Input[0].ConnectorValue < item.Input[1].ConnectorValue) ? 1 : 0;
}
else if (item.LogicalType == LogicalType.GE)
{
output.Value.ConnectorValue = (item.Input[0].ConnectorValue >= item.Input[1].ConnectorValue) ? 1 : 0;
}
else if (item.LogicalType == LogicalType.LE)
{
output.Value.ConnectorValue = (item.Input[0].ConnectorValue <= item.Input[1].ConnectorValue) ? 1 : 0;
}
else if (item.LogicalType == LogicalType.EQ)
{
output.Value.ConnectorValue = (item.Input[0].ConnectorValue == item.Input[1].ConnectorValue) ? 1 : 0;
}
else if (item.LogicalType == LogicalType.NE)
{
output.Value.ConnectorValue = (item.Input[0].ConnectorValue != item.Input[1].ConnectorValue) ? 1 : 0;
}
else if (item.LogicalType == LogicalType.ABS)
{
output.Value.ConnectorValue = Math.Abs(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.SQRT)
{
output.Value.ConnectorValue = Math.Sqrt(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.LN)
{
output.Value.ConnectorValue = Math.Log10(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.LOG)
{
output.Value.ConnectorValue = Math.Log(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.EXP)
{
output.Value.ConnectorValue = Math.Exp(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.SIN)
{
output.Value.ConnectorValue = Math.Sin(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.COS)
{
output.Value.ConnectorValue = Math.Cos(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.TAN)
{
output.Value.ConnectorValue = Math.Tan(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.ASIN)
{
output.Value.ConnectorValue = Math.Asin(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.ACOS)
{
output.Value.ConnectorValue = Math.Acos(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.ATAN)
{
output.Value.ConnectorValue = Math.Atan(item.Input[0].ConnectorValue);
}
else if (item.LogicalType == LogicalType.EXPT)
{
output.Value.ConnectorValue = Math.Exp(item.Input[0].ConnectorValue);
}
if (output.Value.ValueTypePoint == ValueTypePoint.Bool)
{
if (output.Value.ConnectorValue == 0)
{
output.Value.ColorViewModel.FillColor.Color = Colors.Red;
if (item.LogicalType == LogicalType.Output)
{
item.ColorViewModel.FillColor.Color = Colors.Red;
}
}
else
{
output.Value.ColorViewModel.FillColor.Color = Colors.Green;
if (item.LogicalType == LogicalType.Output)
{
item.ColorViewModel.FillColor.Color = Colors.Green;
}
}
}
else
{
output.Value.ColorViewModel.FillColor.Color = Colors.Green;
}
}
}
}
}
private ConnectorViewModel GetSourceItem(FullyCreatedConnectorInfo sinkConnector)
{
foreach (var connector in DiagramViewModel.Items.OfType<ConnectorViewModel>())
{
if (connector.SinkConnectorInfo == sinkConnector)
{
return connector;
}
}
return null;
}
}
}

View File

@@ -0,0 +1,25 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace AIStudio.Wpf.ADiagram.Demos.Logical
{
public class LogicalGateItem : LogicalGateDesignerItemBase
{
public LogicalGateItem()
{
}
public LogicalGateItem(LogicalGateItemViewModel item) : base(item)
{
}
}
}

View File

@@ -0,0 +1,32 @@
using AIStudio.Wpf.ADiagram.Models;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Logical
{
/// <summary>
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
/// ContentControl with the look for this data. This class is also used to allow
/// the popup to be cancelled without applying any changes to the calling ViewModel
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
/// </summary>
public class LinkPointDesignerItemData : TitleBindableBase
{
public LinkPointDesignerItemData(LinkPoint linkPoint)
{
this.LinkPoint = linkPoint;
}
private LinkPoint _linkPoint;
public LinkPoint LinkPoint
{
get
{
return _linkPoint;
}
set
{
SetProperty(ref _linkPoint, value);
}
}
}
}

View File

@@ -0,0 +1,34 @@
using Util.DiagramDesigner;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using AIStudio.Wpf.ADiagram.Models;
namespace AIStudio.Wpf.ADiagram.Demos.Logical
{
/// <summary>
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
/// ContentControl with the look for this data. This class is also used to allow
/// the popup to be cancelled without applying any changes to the calling ViewModel
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
/// </summary>
public class LogicalGateItemData : TitleBindableBase
{
public LogicalGateItemData(IEnumerable<FullyCreatedConnectorInfo> inputvalues)
{
this.InputValues = new ObservableCollection<FullyCreatedConnectorInfo>(inputvalues);
}
private ObservableCollection<FullyCreatedConnectorInfo> _inputValues;
public ObservableCollection<FullyCreatedConnectorInfo> InputValues
{
get
{
return _inputValues;
}
set
{
SetProperty(ref _inputValues, value);
}
}
}
}

View File

@@ -0,0 +1,745 @@
using AIStudio.Wpf.ADiagram.Services;
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Media;
using System.Collections.ObjectModel;
namespace AIStudio.Wpf.ADiagram.Demos.Logical
{
public class LogicalGateItemViewModel : LogicalGateItemViewModelBase
{
protected IUIVisualizerService visualiserService;
public LogicalGateItemViewModel(LogicalType logicalType) : base(logicalType)
{
ColorViewModel.FillColor.Color = Colors.Orange;
}
public LogicalGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
protected override void Init()
{
base.Init();
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
LogicalGateDesignerItemBase designer = designerbase as LogicalGateDesignerItemBase;
this.Value = designer.Value;
}
protected override void ExecuteEditCommand(object parameter)
{
if (LogicalType == LogicalType.Constant)
{
ValueDesignerItemData data = new ValueDesignerItemData(Value);
if (visualiserService.ShowDialog(data) == true)
{
this.Value = data.Value;
}
}
else
{
LogicalGateItemData data = new LogicalGateItemData(Input.Values);
if (visualiserService.ShowDialog(data) == true)
{
}
}
}
}
public class AddGateItemViewModel : LogicalGateItemViewModel
{
public AddGateItemViewModel() : base(LogicalType.ADD)
{
}
public AddGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class SubtractGateItemViewModel : LogicalGateItemViewModel
{
public SubtractGateItemViewModel() : base(LogicalType.SUB)
{
}
public SubtractGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class MultiplyGateItemViewModel : LogicalGateItemViewModel
{
public MultiplyGateItemViewModel() : base(LogicalType.MUL)
{
}
public MultiplyGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class DivideGateItemViewModel : LogicalGateItemViewModel
{
public DivideGateItemViewModel() : base(LogicalType.DIV)
{
}
public DivideGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class AverageGateItemViewModel : LogicalGateItemViewModel
{
public AverageGateItemViewModel() : base(LogicalType.AVE)
{
}
public AverageGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class MODGateItemViewModel : LogicalGateItemViewModel
{
public MODGateItemViewModel() : base(LogicalType.MOD)
{
}
public MODGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class ANDGateItemViewModel : LogicalGateItemViewModel
{
public ANDGateItemViewModel() : base(LogicalType.AND)
{
}
public ANDGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class ORGateItemViewModel : LogicalGateItemViewModel
{
public ORGateItemViewModel() : base(LogicalType.OR)
{
}
public ORGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class XORGateItemViewModel : LogicalGateItemViewModel
{
public XORGateItemViewModel() : base(LogicalType.XOR)
{
}
public XORGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class NOTGateItemViewModel : LogicalGateItemViewModel
{
public NOTGateItemViewModel() : base(LogicalType.NOT)
{
}
public NOTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class SHLGateItemViewModel : LogicalGateItemViewModel
{
public SHLGateItemViewModel() : base(LogicalType.SHL)
{
}
public SHLGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class SHRGateItemViewModel : LogicalGateItemViewModel
{
public SHRGateItemViewModel() : base(LogicalType.SHR)
{
}
public SHRGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class ROLGateItemViewModel : LogicalGateItemViewModel
{
public ROLGateItemViewModel() : base(LogicalType.ROL)
{
}
public ROLGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class RORGateItemViewModel : LogicalGateItemViewModel
{
public RORGateItemViewModel() : base(LogicalType.ROR)
{
}
public RORGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class SELGateItemViewModel : LogicalGateItemViewModel
{
public SELGateItemViewModel() : base(LogicalType.SEL)
{
}
public SELGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class MAXGateItemViewModel : LogicalGateItemViewModel
{
public MAXGateItemViewModel() : base(LogicalType.MAX)
{
}
public MAXGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class MINGateItemViewModel : LogicalGateItemViewModel
{
public MINGateItemViewModel() : base(LogicalType.MIN)
{
}
public MINGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class LIMITGateItemViewModel : LogicalGateItemViewModel
{
public LIMITGateItemViewModel() : base(LogicalType.LIMIT)
{
}
public LIMITGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class GTGateItemViewModel : LogicalGateItemViewModel
{
public GTGateItemViewModel() : base(LogicalType.GT)
{
}
public GTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class LTGateItemViewModel : LogicalGateItemViewModel
{
public LTGateItemViewModel() : base(LogicalType.GT)
{
}
public LTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class GEGateItemViewModel : LogicalGateItemViewModel
{
public GEGateItemViewModel() : base(LogicalType.GE)
{
}
public GEGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class LEGateItemViewModel : LogicalGateItemViewModel
{
public LEGateItemViewModel() : base(LogicalType.LE)
{
}
public LEGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class EQGateItemViewModel : LogicalGateItemViewModel
{
public EQGateItemViewModel() : base(LogicalType.LE)
{
}
public EQGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class NEGateItemViewModel : LogicalGateItemViewModel
{
public NEGateItemViewModel() : base(LogicalType.NE)
{
}
public NEGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class ABSGateItemViewModel : LogicalGateItemViewModel
{
public ABSGateItemViewModel() : base(LogicalType.ABS)
{
}
public ABSGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class SQRTGateItemViewModel : LogicalGateItemViewModel
{
public SQRTGateItemViewModel() : base(LogicalType.SQRT)
{
}
public SQRTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class LNGateItemViewModel : LogicalGateItemViewModel
{
public LNGateItemViewModel() : base(LogicalType.LN)
{
}
public LNGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class LOGGateItemViewModel : LogicalGateItemViewModel
{
public LOGGateItemViewModel() : base(LogicalType.LOG)
{
}
public LOGGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class EXPGateItemViewModel : LogicalGateItemViewModel
{
public EXPGateItemViewModel() : base(LogicalType.EXP)
{
}
public EXPGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class SINGateItemViewModel : LogicalGateItemViewModel
{
public SINGateItemViewModel() : base(LogicalType.SIN)
{
}
public SINGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class COSGateItemViewModel : LogicalGateItemViewModel
{
public COSGateItemViewModel() : base(LogicalType.COS)
{
}
public COSGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class TANGateItemViewModel : LogicalGateItemViewModel
{
public TANGateItemViewModel() : base(LogicalType.TAN)
{
}
public TANGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class ASINGateItemViewModel : LogicalGateItemViewModel
{
public ASINGateItemViewModel() : base(LogicalType.ASIN)
{
}
public ASINGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class ACOSGateItemViewModel : LogicalGateItemViewModel
{
public ACOSGateItemViewModel() : base(LogicalType.ACOS)
{
}
public ACOSGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class ATANGateItemViewModel : LogicalGateItemViewModel
{
public ATANGateItemViewModel() : base(LogicalType.ATAN)
{
}
public ATANGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class EXPTGateItemViewModel : LogicalGateItemViewModel
{
public EXPTGateItemViewModel() : base(LogicalType.EXPT)
{
}
public EXPTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class ConstantDesignerItemViewModel : LogicalGateItemViewModel
{
public ConstantDesignerItemViewModel() : base(LogicalType.Constant)
{
ItemHeight = 28;
}
public ConstantDesignerItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
}
public class InputItemViewModel : LogicalGateItemViewModel
{
public InputItemViewModel() : base(LogicalType.Input)
{
ItemHeight = 28;
}
public InputItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
LogicalGateDesignerItemBase designer = designerbase as LogicalGateDesignerItemBase;
this.Value = designer.Value;
LinkPoint = LogicalService.LinkPoint.FirstOrDefault(p => p.Id.ToString() == designer.Icon); //不想新增字段了就用这个Icon保存自定义测点的Id吧。
if (LinkPoint != null)
{
LinkPoint.Value = designer.Value;
}
}
private LinkPoint _linkPoint;
public LinkPoint LinkPoint
{
get { return _linkPoint; }
set
{
if (SetProperty(ref _linkPoint, value))
{
Icon = _linkPoint?.Id.ToString();//不想新增字段了就用这个Icon保存自定义测点的Id吧。
Text = _linkPoint?.Name;
}
}
}
protected override void ExecuteEditCommand(object parameter)
{
LinkPointDesignerItemData data = new LinkPointDesignerItemData(LinkPoint);
if (visualiserService.ShowDialog(data) == true)
{
this.LinkPoint = data.LinkPoint;
}
}
}
public class OutputItemViewModel : LogicalGateItemViewModel
{
public OutputItemViewModel() : base(LogicalType.Output)
{
ItemHeight = 28;
}
public OutputItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
LogicalGateDesignerItemBase designer = designerbase as LogicalGateDesignerItemBase;
this.Value = designer.Value;
LinkPoint = LogicalService.LinkPoint.FirstOrDefault(p => p.Id.ToString() == designer.Icon); //不想新增字段了就用这个Icon保存自定义测点的Id吧。
if (LinkPoint != null)
{
LinkPoint.Value = designer.Value;
}
}
private LinkPoint _linkPoint;
public LinkPoint LinkPoint
{
get { return _linkPoint; }
set
{
if (SetProperty(ref _linkPoint, value))
{
Icon = _linkPoint?.Id.ToString();//不想新增字段了就用这个Icon保存自定义测点的Id吧。
Text = _linkPoint?.Name;
}
}
}
protected override void ExecuteEditCommand(object parameter)
{
LinkPointDesignerItemData data = new LinkPointDesignerItemData(LinkPoint);
if (visualiserService.ShowDialog(data) == true)
{
this.LinkPoint = data.LinkPoint;
}
}
}
public class TimerDesignerItemViewModel : LogicalGateItemViewModel
{
private System.Timers.Timer readDataTimer = new System.Timers.Timer();
public Action Do;
public TimerDesignerItemViewModel() : base(LogicalType.Time)
{
ItemHeight = 32;
ItemWidth = 32;
Value = 1;
Start();
BuildMenuOptions();
}
public TimerDesignerItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
BuildMenuOptions();
}
protected override void Init()
{
MenuItemCommand = new SimpleCommand(ExecuteMenuItemCommand);
base.Init();
readDataTimer.Elapsed += timeCycle;
readDataTimer.Interval = 1000;
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
if (IsEnabled)
{
Start();
}
else
{
Stop();
}
}
private void Start()
{
IsEnabled = true;
Output[0].ColorViewModel.FillColor.Color = Colors.Green;
readDataTimer.Start();
}
private void Stop()
{
IsEnabled = false;
Output[0].ColorViewModel.FillColor.Color = Colors.Red;
readDataTimer.Stop();
}
private void ExecuteMenuItemCommand(object obj)
{
if ((obj as CinchMenuItem).IsChecked == true)
{
Start();
}
else
{
Stop();
}
}
public SimpleCommand MenuItemCommand { get; private set; }
private void BuildMenuOptions()
{
menuOptions = new ObservableCollection<CinchMenuItem>();
CinchMenuItem menuItem = new CinchMenuItem();
menuItem.Text = "启动";
menuItem.IsCheckable = true;
menuItem.IsChecked = IsEnabled;
menuItem.Command = MenuItemCommand;
menuItem.CommandParameter = menuItem;
menuOptions.Add(menuItem);
}
protected override void ExecuteEditCommand(object parameter)
{
ValueDesignerItemData data = new ValueDesignerItemData(Value);
if (visualiserService.ShowDialog(data) == true)
{
this.Value = data.Value;
readDataTimer.Interval = this.Value * 1000;
}
}
private void timeCycle(object sender, EventArgs e)
{
Output.FirstOrDefault().Value.ConnectorValue += Value;
if (Do != null)
{
Do();
}
}
public override void Dispose()
{
base.Dispose();
readDataTimer.Dispose();
}
}
}

View File

@@ -0,0 +1,101 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Logical"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
xmlns:dd="https://astudio.github.io/diagram"
xmlns:Fluent="urn:fluent-ribbon"
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
<DataTemplate DataType="{x:Type model:LogicalGateItemViewModel}">
<Grid IsHitTestVisible="False">
<Rectangle StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
<TextBlock Text="{Binding LogicalType}" Foreground="{Binding FontViewModel.FontColor,Converter={StaticResource ColorBrushConverter}}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
<TextBlock Text="{Binding OrderNumber,StringFormat={}{0}#}" Foreground="Blue" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="2"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type model:LogicalGateItemData}">
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
<ListBox ItemsSource="{Binding InputValues}" AlternationCount="{Binding InputValues.Count}" Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="输入" VerticalAlignment="Center"/>
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplatedParent.(ItemsControl.AlternationIndex)}" VerticalAlignment="Center" Margin="0,0,5,0"/>
<TextBox Width="100" Text="{Binding ConnectorValue,Mode=TwoWay}"></TextBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type model:ConstantDesignerItemViewModel}">
<Grid IsHitTestVisible="False">
<Rectangle StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
<TextBlock Text="{Binding Value}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type model:ValueDesignerItemData}">
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Content="Value"
Margin="5" />
<TextBox Grid.Column="1"
Text="{Binding Value}" VerticalAlignment="Center"
Margin="5"
FontSize="12"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type model:LinkPointDesignerItemData}">
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Content="LinkPoint"
Margin="5" />
<ComboBox Grid.Column="1"
SelectedItem="{Binding LinkPoint}" ItemsSource="{x:Static model:LogicalService.LinkPoint}" VerticalAlignment="Center" DisplayMemberPath="Name"
Margin="5"
FontSize="12"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type model:InputItemViewModel}">
<Grid IsHitTestVisible="False">
<Rectangle StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
<TextBlock Text="{Binding Text,TargetNullValue='[Null]'}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type model:OutputItemViewModel}">
<Grid IsHitTestVisible="False">
<Rectangle StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
<TextBlock Text="{Binding Text,TargetNullValue='[Null]'}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type model:TimerDesignerItemViewModel}">
<Grid IsHitTestVisible="False">
<Ellipse StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
<TextBlock Text="{Binding Value,StringFormat={}{0}s}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
</Grid>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,32 @@
using AIStudio.Wpf.ADiagram.Models;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Logical
{
/// <summary>
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
/// ContentControl with the look for this data. This class is also used to allow
/// the popup to be cancelled without applying any changes to the calling ViewModel
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
/// </summary>
public class ValueDesignerItemData : TitleBindableBase
{
public ValueDesignerItemData(double value)
{
this.Value = value;
}
private double _value;
public double Value
{
get
{
return _value;
}
set
{
SetProperty(ref _value, value);
}
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class PathDesignerItem : DesignerItemBase
{
public PathDesignerItem()
{
}
public PathDesignerItem(DesignerItemViewModelBase item) : base(item) { }
}
}

View File

@@ -0,0 +1,25 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class PersistDesignerItem : DesignerItemBase
{
public PersistDesignerItem()
{
}
public PersistDesignerItem(PersistDesignerItemViewModel item) : base(item)
{
this.HostUrl = item.HostUrl;
}
[XmlAttribute]
public string HostUrl { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class SettingsDesignerItem : DesignerItemBase
{
public SettingsDesignerItem()
{
}
public SettingsDesignerItem(SettingsDesignerItemViewModel item) : base(item)
{
this.Setting = item.Setting;
}
public string Setting { get; set; }
}
}

View File

@@ -0,0 +1,93 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using AIStudio.Wpf.ADiagram.Commands;
using System.Windows.Input;
using AIStudio.Wpf.ADiagram.Models;
using ZXing;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class BarcodeDesignerItemData : TitleBindableBase
{
public BarcodeDesignerItemData()
{
}
public BarcodeDesignerItemData(BarcodeDesignerItemViewModel item)
{
this.Title = "二维码";
this.Text = item.Text;
this.Icon = item.Icon;
this.Margin = item.Margin;
this.Format = item.Format;
}
public BarcodeFormat Format { get; set; }
private string _text;
public string Text
{
get
{
return _text;
}
set
{
SetProperty(ref _text, value);
}
}
private double _margin;
public double Margin
{
get
{
return _margin;
}
set
{
SetProperty(ref _margin, value);
}
}
private string _icon;
public string Icon
{
get
{
return _icon;
}
set
{
SetProperty(ref _icon, value);
}
}
private ICommand _iploadCommand;
public ICommand UploadCommand
{
get
{
return this._iploadCommand ?? (this._iploadCommand = new DelegateCommand(() => this.Upload()));
}
}
private void Upload()
{
Microsoft.Win32.OpenFileDialog openFile = new Microsoft.Win32.OpenFileDialog();
openFile.Filter = "图片|*.bmp;*.jpg;*.jpeg;*.gif;*.png";
if (openFile.ShowDialog() == true)
{
Icon = openFile.FileName;
}
}
}
}

View File

@@ -0,0 +1,87 @@
using AIStudio.Wpf.ADiagram.Services;
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;
using System.Globalization;
using ZXing;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class BarcodeDesignerItemViewModel : DesignerItemViewModelBase
{
private IUIVisualizerService visualiserService;
public BarcodeDesignerItemViewModel() : base()
{
}
public BarcodeDesignerItemViewModel(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
protected override void Init()
{
base.Init();
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
Format = (BarcodeFormat)Enum.Parse(typeof(BarcodeFormat), (designerbase as DesignerItemBase).Reserve.ToString());
ShowText = false;
}
public void AutoSize()
{
ItemWidth = 140;
ItemHeight = 140;
}
protected override void ExecuteEditCommand(object parameter)
{
EditData();
}
public override bool InitData()
{
if (string.IsNullOrEmpty(Icon))
return EditData();
return true;
}
public BarcodeFormat Format { get; set; } = BarcodeFormat.QR_CODE;
public override bool EditData()
{
if (IsReadOnly == true) return false;
BarcodeDesignerItemData data = new BarcodeDesignerItemData(this);
if (visualiserService.ShowDialog(data) == true)
{
bool needauto = Text == null;
Text = data.Text;
ShowText = false;
Icon = data.Icon;
Margin = data.Margin;
if (needauto)
{
AutoSize();
}
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,50 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
xmlns:dd="https://astudio.github.io/diagram"
xmlns:Fluent="urn:fluent-ribbon"
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
<DataTemplate DataType="{x:Type model:BarcodeDesignerItemViewModel}">
<Viewbox Stretch="Fill" IsHitTestVisible="False">
<controls:Barcode Width="{Binding ItemWidth}" Height="{Binding ItemHeight}" Padding="{Binding Margin,Converter={StaticResource DoubleToThickness}}" Text="{Binding Text}" Icon="{Binding Icon}" Format="{Binding Format}"/>
</Viewbox>
</DataTemplate>
<!-- DataTemplate for Popup look and feel -->
<DataTemplate DataType="{x:Type model:BarcodeDesignerItemData}">
<Grid Width="550">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Content="网页链接"
Margin="5" />
<DockPanel Grid.Row="1" >
<Border BorderThickness="1" BorderBrush="Black" Margin="5" DockPanel.Dock="Right">
<controls:Barcode Text="{Binding Text}" Icon="{Binding Icon}" Format="{Binding Format}" Width="140" Height="140" Padding="{Binding Margin,Converter={StaticResource DoubleToThickness}}" />
</Border>
<TextBox Text="{Binding Text,UpdateSourceTrigger=PropertyChanged}" TextWrapping="Wrap" DockPanel.Dock="Left" Margin="5"/>
</DockPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock Text="边界:" Margin="5" HorizontalAlignment="Center"/>
<Fluent:Spinner Margin="5" DockPanel.Dock="Right" Width="60" Size="Small" Value="{Binding Margin}" Maximum="25" Minimum="0" Format="0 px" />
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Margin="5,5,50,5" Content="上传Logo" Command="{Binding UploadCommand}" />
</StackPanel>
</Grid>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,54 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using AIStudio.Wpf.ADiagram.Models;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class OutLineTextDesignerItemData : TitleBindableBase
{
public OutLineTextDesignerItemData()
{
}
public OutLineTextDesignerItemData(OutLineTextDesignerItemViewModel item)
{
this.Title = "矢量文本";
this.Text = item.Text;
this.FontViewModel = CopyHelper.Mapper<FontViewModel, IFontViewModel>(item.FontViewModel);
}
private IFontViewModel _fontViewModel;
public IFontViewModel FontViewModel
{
get
{
return _fontViewModel;
}
set
{
SetProperty(ref _fontViewModel, value);
}
}
private string _text;
public string Text
{
get
{
return _text;
}
set
{
SetProperty(ref _text, value);
}
}
}
}

View File

@@ -0,0 +1,87 @@
using AIStudio.Wpf.ADiagram.Services;
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;
using System.Globalization;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class OutLineTextDesignerItemViewModel : TextDesignerItemViewModel
{
private IUIVisualizerService visualiserService;
public OutLineTextDesignerItemViewModel(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
public OutLineTextDesignerItemViewModel() : base()
{
}
protected override void Init()
{
base.Init();
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
FontViewModel.FontFamily = "Arial";
FontViewModel.FontSize = 36;
}
public void AutoSize()
{
var size = MeasureString();
ItemWidth = size.Width;
ItemHeight = size.Height;
}
private Size MeasureString()
{
var formattedText = new FormattedText(
Text,
CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch),
FontViewModel.FontSize,
Brushes.Black);
return new Size(formattedText.Width, formattedText.Height);
}
protected override void ExecuteEditCommand(object parameter)
{
EditData();
}
public override bool InitData()
{
if (string.IsNullOrEmpty(Text))
return EditData();
return true;
}
public override bool EditData()
{
if (IsReadOnly == true) return false;
OutLineTextDesignerItemData data = new OutLineTextDesignerItemData(this);
if (visualiserService.ShowDialog(data) == true)
{
Text = data.Text;
FontViewModel = CopyHelper.Mapper<FontViewModel, IFontViewModel>(data.FontViewModel);
AutoSize();
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,113 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
xmlns:dd="https://astudio.github.io/diagram"
xmlns:Fluent="urn:fluent-ribbon"
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
<DataTemplate DataType="{x:Type model:OutLineTextDesignerItemViewModel}">
<Viewbox Stretch="Fill" IsHitTestVisible="False">
<controls:OutlineText StrokePosition="Outside"
Text="{Binding Text}"
FontSize="{Binding FontViewModel.FontSize}"
FontFamily="{Binding FontViewModel.FontFamily}"
FontWeight="{Binding FontViewModel.FontWeight}"
FontStyle="{Binding FontViewModel.FontStyle}"
FontStretch="{Binding FontViewModel.FontStretch}"
TextDecorations="{Binding FontViewModel.TextDecorations}"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}"
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"/>
</Viewbox>
</DataTemplate>
<!-- DataTemplate for Popup look and feel -->
<DataTemplate DataType="{x:Type model:OutLineTextDesignerItemData}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Content="添加文本"
Margin="5" />
<TextBox Grid.Row="1"
Text="{Binding Text}"
FontSize="{Binding ElementName=comboBoxFontSize,Path=SelectedItem}"
FontFamily="{Binding ElementName=comboBoxFontName,Path=SelectedItem}"
FontWeight="{Binding ElementName=buttonBold,Path=IsChecked,Converter={converter:ConverterBoolToValueMap Parameter='Regular'}, ConverterParameter='Bold'}"
FontStyle="{Binding ElementName=buttonItalic,Path=IsChecked,Converter={converter:ConverterBoolToValueMap Parameter='Normal'}, ConverterParameter='Italic'}"
TextDecorations="{Binding ElementName=buttonUnderline,Path=IsChecked,Converter={converter:ConverterBoolToValueMap Parameter='None'}, ConverterParameter='Underline'}"
Height="100"
Margin="5"
TextWrapping="Wrap"/>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<Fluent:ComboBox x:Name="comboBoxFontName"
Margin="5"
MinWidth="49"
Height="22"
BorderBrush="Gainsboro"
IsTextSearchEnabled="True"
ResizeMode="Vertical"
KeyTip="FF"
SizeDefinition="Small"
ScrollViewer.CanContentScroll="False"
ItemsSource="{x:Static dd:FontViewModel.FontFamilys}"
SelectedItem="{Binding FontViewModel.FontFamily}">
<Fluent:ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"
FontFamily="{Binding}" />
</DataTemplate>
</Fluent:ComboBox.ItemTemplate>
</Fluent:ComboBox>
<Fluent:ComboBox x:Name="comboBoxFontSize"
Margin="5"
Width="49"
HorizontalAlignment="Left"
Height="22"
BorderBrush="Gainsboro"
IsEditable="True"
SizeDefinition="Small"
ResizeMode="Vertical"
KeyTip="FS"
ItemsSource="{x:Static dd:FontViewModel.FontSizes}"
SelectedItem="{Binding FontViewModel.FontSize}">
<Fluent:ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</Fluent:ComboBox.ItemTemplate>
</Fluent:ComboBox>
<Fluent:ToggleButton KeyTip="B"
x:Name="buttonBold"
Icon="pack://application:,,,/AIStudio.Wpf.ADiagram;component/Images/Bold.png"
HorizontalAlignment="Left"
SizeDefinition="Small"
IsChecked="{Binding FontViewModel.FontWeight,Converter={converter:ConverterValueMapToBool Parameter='Regular'}, ConverterParameter='Bold'}"/>
<Fluent:ToggleButton x:Name="buttonItalic"
KeyTip="I"
Icon="pack://application:,,,/AIStudio.Wpf.ADiagram;component/Images/Italic.png"
HorizontalAlignment="Left"
SizeDefinition="Small"
IsChecked="{Binding FontViewModel.FontStyle,Converter={converter:ConverterValueMapToBool Parameter='Normal'}, ConverterParameter='Italic'}"/>
<Fluent:ToggleButton x:Name="buttonUnderline"
KeyTip="U"
Icon="pack://application:,,,/AIStudio.Wpf.ADiagram;component/Images/Underline.png"
HorizontalAlignment="Left"
SizeDefinition="Small"
IsChecked="{Binding FontViewModel.Underline}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,30 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class PathItemViewModel : DesignerItemViewModelBase
{
public PathItemViewModel() : base()
{
}
public PathItemViewModel(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
{
}
protected override void Init()
{
base.Init();
this.ShowConnectors = false;
}
}
}

View File

@@ -0,0 +1,34 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
xmlns:convent="clr-namespace:AIStudio.Wpf.ADiagram.Converters">
<convent:StringPathConverter x:Key="stringPathConverter"/>
<s:ColorBrushConverter x:Key="ColorBrushConverter" />
<Brush x:Key="ItemStroke">#FFD69436</Brush>
<LinearGradientBrush x:Key="ItemBrush" StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#FAFBE9" Offset="0" />
<GradientStop Color="Orange" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<Style x:Key="PathItemStyle" TargetType="Path">
<!--<Setter Property="Fill" Value="{StaticResource ItemBrush}"/>
<Setter Property="Stroke" Value="{StaticResource ItemStroke}"/>-->
<Setter Property="Fill" Value="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"/>
<Setter Property="Stroke" Value="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"/>
<Setter Property="StrokeThickness" Value="1"/>
<Setter Property="StrokeLineJoin" Value="Round"/>
<Setter Property="Stretch" Value="Fill"/>
<Setter Property="IsHitTestVisible" Value="True"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Data" Value="{Binding Icon,Converter={StaticResource stringPathConverter}}"/>
</Style>
<DataTemplate DataType="{x:Type model:PathItemViewModel}">
<Grid>
<Path Tag="Process" IsHitTestVisible="False" Style="{StaticResource PathItemStyle}"/>
</Grid>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,39 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AIStudio.Wpf.ADiagram.Models;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
/// <summary>
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
/// ContentControl with the look for this data. This class is also used to allow
/// the popup to be cancelled without applying any changes to the calling ViewModel
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
/// </summary>
public class PersistDesignerItemData : TitleBindableBase
{
public PersistDesignerItemData(string currentHostUrl)
{
HostUrl = currentHostUrl;
}
private string _hostUrl = "";
public string HostUrl
{
get
{
return _hostUrl;
}
set
{
SetProperty(ref _hostUrl, value);
}
}
}
}

View File

@@ -0,0 +1,58 @@
using AIStudio.Wpf.ADiagram.Services;
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Media;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class PersistDesignerItemViewModel : DesignerItemViewModelBase
{
private IUIVisualizerService visualiserService;
public PersistDesignerItemViewModel(IDiagramViewModel parent, PersistDesignerItem designer) : base(parent, designer)
{
}
public PersistDesignerItemViewModel() : base()
{
}
protected override void Init()
{
base.Init();
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
this.ShowConnectors = false;
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
PersistDesignerItem designer = designerbase as PersistDesignerItem;
this.HostUrl = designer.HostUrl;
}
public string HostUrl { get; set; }
protected override void ExecuteEditCommand(object parameter)
{
PersistDesignerItemData data = new PersistDesignerItemData(HostUrl);
if (visualiserService.ShowDialog(data) == true)
{
this.HostUrl = data.HostUrl;
}
}
}
}

View File

@@ -0,0 +1,80 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
xmlns:dd="https://astudio.github.io/diagram"
xmlns:Fluent="urn:fluent-ribbon"
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
<ControlTemplate x:Key="infoButtonTemplate" TargetType="Button">
<Grid x:Name="grid" Opacity="0.1">
<Ellipse Width="16"
Height="16"
Stroke="Black"
StrokeThickness="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="White"/>
<Label Content="i"
FontWeight="Bold"
FontStyle="Italic"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
FontSize="12" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="grid"
Property="Opacity"
Value="1.0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- DataTemplate for DesignerCanvas look and feel -->
<DataTemplate DataType="{x:Type model:PersistDesignerItemViewModel}">
<Grid>
<Image IsHitTestVisible="False"
Stretch="Fill"
Source="/AIStudio.Wpf.ADiagram;component/Images/Persist.png"
Tag="setting" />
<Button x:Name="btnSetting" HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="5"
Template="{StaticResource infoButtonTemplate}"
Command="{Binding EditCommand}" />
</Grid>
</DataTemplate>
<!-- DataTemplate for Popup look and feel -->
<DataTemplate DataType="{x:Type model:PersistDesignerItemData}">
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Content="HostUrl"
Margin="5" />
<TextBox Grid.Row="1"
HorizontalAlignment="Left"
Text="{Binding HostUrl}"
Width="150"
Margin="5" />
</Grid>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,39 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AIStudio.Wpf.ADiagram.Models;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
/// <summary>
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
/// ContentControl with the look for this data. This class is also used to allow
/// the popup to be cancelled without applying any changes to the calling ViewModel
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
/// </summary>
public class SettingsDesignerItemData : TitleBindableBase
{
public SettingsDesignerItemData(string currentSetting1)
{
Setting1 = currentSetting1;
}
private string _setting1 = "";
public string Setting1
{
get
{
return _setting1;
}
set
{
SetProperty(ref _setting1, value);
}
}
}
}

View File

@@ -0,0 +1,56 @@
using AIStudio.Wpf.ADiagram.Services;
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Media;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class SettingsDesignerItemViewModel : DesignerItemViewModelBase
{
private IUIVisualizerService visualiserService;
public SettingsDesignerItemViewModel(IDiagramViewModel parent, SettingsDesignerItem designer) : base(parent, designer)
{
}
public SettingsDesignerItemViewModel() : base()
{
}
protected override void Init()
{
base.Init();
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
this.ShowConnectors = false;
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
SettingsDesignerItem designer = designerbase as SettingsDesignerItem;
this.Setting = designer.Setting;
}
public String Setting{ get; set; }
protected override void ExecuteEditCommand(object parameter)
{
SettingsDesignerItemData data = new SettingsDesignerItemData(Setting);
if (visualiserService.ShowDialog(data) == true)
{
this.Setting = data.Setting1;
}
}
}
}

View File

@@ -0,0 +1,80 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
xmlns:dd="https://astudio.github.io/diagram"
xmlns:Fluent="urn:fluent-ribbon"
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
<ControlTemplate x:Key="infoButtonTemplate" TargetType="Button">
<Grid x:Name="grid" Opacity="0.1">
<Ellipse Width="16"
Height="16"
Stroke="Black"
StrokeThickness="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="White"/>
<Label Content="i"
FontWeight="Bold"
FontStyle="Italic"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
FontSize="12" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="grid"
Property="Opacity"
Value="1.0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- DataTemplate for DesignerCanvas look and feel -->
<DataTemplate DataType="{x:Type model:SettingsDesignerItemViewModel}">
<Grid>
<Image IsHitTestVisible="False"
Stretch="Fill"
Source="/AIStudio.Wpf.ADiagram;component/Images/Setting.png"
Tag="setting" />
<Button HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="5"
Template="{StaticResource infoButtonTemplate}"
Command="{Binding EditCommand}" />
</Grid>
</DataTemplate>
<!-- DataTemplate for Popup look and feel -->
<DataTemplate DataType="{x:Type model:SettingsDesignerItemData}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Content="Setting1"
Margin="5" />
<TextBox Grid.Row="1"
HorizontalAlignment="Left"
Text="{Binding Setting}"
Width="150"
Margin="5" />
</Grid>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Util.DiagramDesigner;
namespace AIStudio.Wpf.ADiagram.Demos.Others
{
public class SvgDesignerItemViewModel: MediaItemViewModel
{
protected override string Filter { get; set; } = "Svg|*.svg";
public SvgDesignerItemViewModel() : base()
{
}
public SvgDesignerItemViewModel(IDiagramViewModel parent, MediaDesignerItem designer) : base(parent, designer)
{
}
}
}

View File

@@ -0,0 +1,13 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
xmlns:svg="clr-namespace:Svg2XamlTestExtension;assembly=Svg2XamlTestExtension">
<s:ColorBrushConverter x:Key="ColorBrushConverter" />
<DataTemplate DataType="{x:Type model:SvgDesignerItemViewModel}">
<Grid IsHitTestVisible="False">
<svg:PackSvg Width="Auto" Height="Auto" Path="{Binding Icon}" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"/>
</Grid>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,172 @@
{
"Title": null,
"DiagramType": 0,
"DiagramItems": [
{
"Name": null,
"DiagramType": 0,
"DesignerItems": [
],
"PersistDesignerItems": [
],
"SettingsDesignerItems": [
],
"PathDesignerItems": [
{
"Left": 132.80000000000007,
"Top": 101.26000022888184,
"ScaleX": 1,
"ScaleY": 1,
"Margin": 0.0,
"ItemWidth": 65.0,
"ItemHeight": 65.0,
"Icon": "M 0,0 H 60 V 40 C 30,30 30,50 0,40 Z",
"ItemTypeName": "AIStudio.Wpf.ADiagram.Demos.Others.PathItemViewModel",
"Id": "da395032-ad9e-4dab-a035-f59bed5cb4c4",
"ZIndex": 0,
"IsGroup": false,
"ParentId": "00000000-0000-0000-0000-000000000000",
"Text": "欢迎来到AIStudio画板",
"ColorItem": {
"LineColor": {
"BrushType": 1,
"Color": "#FF808080",
"GradientStop": null,
"Offset": null,
"Image": null,
"SubType": 0,
"StartPoint": "0,0",
"EndPoint": "0,0",
"Opacity": 1.0,
"LinearOrientation": 0,
"RadialOrientation": 0,
"Angle": 0
},
"FillColor": {
"BrushType": 1,
"Color": "#FFFFA500",
"GradientStop": null,
"Offset": null,
"Image": null,
"SubType": 0,
"StartPoint": "0,0",
"EndPoint": "0,0",
"Opacity": 1.0,
"LinearOrientation": 0,
"RadialOrientation": 0,
"Angle": 0
},
"ShadowColor": "#00FFFFFF",
"LineWidth": 1.0,
"LeftArrowPathStyle": 0,
"RightArrowPathStyle": 1,
"LeftArrowSizeStyle": 10,
"RightArrowSizeStyle": 10
},
"FontItem": {
"FontWeight": "Normal",
"FontStyle": "Normal",
"FontStretch": "Normal",
"Underline": false,
"Strikethrough": false,
"OverLine": false,
"FontColor": "#FF000000",
"FontFamily": "Arial",
"FontSize": 11.0,
"FontObject": "Arial, 11pt",
"TextEffectColor": "#00FFFFFF",
"HighlightColor": "#00FFFFFF",
"FontCase": 0,
"HorizontalAlignment": 1,
"VerticalAlignment": 1,
"LineHeight": 0.0
}
}
],
"MediaDesignerItems": [
],
"ImageDesignerItems": [
],
"TextDesignerItems": [
],
"LogicalGateItems": [
],
"FlowNodeDesignerItems": [
],
"AllDesignerItems": [
{
"Left": 132.80000000000007,
"Top": 101.26000022888184,
"Margin": 0.0,
"ItemWidth": 65.0,
"ItemHeight": 65.0,
"Icon": "M 0,0 H 60 V 40 C 30,30 30,50 0,40 Z",
"ItemTypeName": "AIStudio.Wpf.ADiagram.Demos.Others.PathItemViewModel",
"Id": "da395032-ad9e-4dab-a035-f59bed5cb4c4",
"ZIndex": 0,
"IsGroup": false,
"ParentId": "00000000-0000-0000-0000-000000000000",
"Text": "欢迎来到AIStudio画板",
"ColorItem": {
"LineColor": {
"BrushType": 1,
"Color": "#FF808080",
"GradientStop": null,
"Offset": null,
"Image": null,
"SubType": 0,
"StartPoint": "0,0",
"EndPoint": "0,0",
"Opacity": 1.0,
"LinearOrientation": 0,
"RadialOrientation": 0,
"Angle": 0
},
"FillColor": {
"BrushType": 1,
"Color": "#FFFFA500",
"GradientStop": null,
"Offset": null,
"Image": null,
"SubType": 0,
"StartPoint": "0,0",
"EndPoint": "0,0",
"Opacity": 1.0,
"LinearOrientation": 0,
"RadialOrientation": 0,
"Angle": 0
},
"ShadowColor": "#00FFFFFF",
"LineWidth": 1.0,
"LeftArrowPathStyle": 0,
"RightArrowPathStyle": 1,
"LeftArrowSizeStyle": 10,
"RightArrowSizeStyle": 10
},
"FontItem": {
"FontWeight": "Normal",
"FontStyle": "Normal",
"FontStretch": "Normal",
"Underline": false,
"Strikethrough": false,
"OverLine": false,
"FontColor": "#FF000000",
"FontFamily": "Arial",
"FontSize": 11.0,
"FontObject": "Arial, 11pt",
"TextEffectColor": "#00FFFFFF",
"HighlightColor": "#00FFFFFF",
"FontCase": 0,
"HorizontalAlignment": 1,
"VerticalAlignment": 1,
"LineHeight": 0.0
}
}
],
"ConnectionIds": [
],
"Connections": [
]
}
]
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.ADiagram.Enums
{
public enum ColorType
{
Fill,
Line,
Text,
}
}

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