mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-03-02 07:40:54 +08:00
添加项目文件。
This commit is contained in:
66
.gitattributes
vendored
Normal file
66
.gitattributes
vendored
Normal 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
264
.gitignore
vendored
Normal 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
|
||||
923
AIStudio.Wpf.ADiagram/AIStudio.Wpf.ADiagram.csproj
Normal file
923
AIStudio.Wpf.ADiagram/AIStudio.Wpf.ADiagram.csproj
Normal 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>
|
||||
28
AIStudio.Wpf.ADiagram/App.config
Normal file
28
AIStudio.Wpf.ADiagram/App.config
Normal 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>
|
||||
15
AIStudio.Wpf.ADiagram/App.xaml
Normal file
15
AIStudio.Wpf.ADiagram/App.xaml
Normal 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>
|
||||
42
AIStudio.Wpf.ADiagram/App.xaml.cs
Normal file
42
AIStudio.Wpf.ADiagram/App.xaml.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
82
AIStudio.Wpf.ADiagram/ApplicationServicesProvider.cs
Normal file
82
AIStudio.Wpf.ADiagram/ApplicationServicesProvider.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
10
AIStudio.Wpf.ADiagram/AssemblyInfo.cs
Normal file
10
AIStudio.Wpf.ADiagram/AssemblyInfo.cs
Normal 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)
|
||||
)]
|
||||
908
AIStudio.Wpf.ADiagram/Commands/CanExecuteDelegateCommand.cs
Normal file
908
AIStudio.Wpf.ADiagram/Commands/CanExecuteDelegateCommand.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
69
AIStudio.Wpf.ADiagram/Commands/CommandReference.cs
Normal file
69
AIStudio.Wpf.ADiagram/Commands/CommandReference.cs
Normal 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
|
||||
}
|
||||
}
|
||||
240
AIStudio.Wpf.ADiagram/Commands/CompositeCommand.cs
Normal file
240
AIStudio.Wpf.ADiagram/Commands/CompositeCommand.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
334
AIStudio.Wpf.ADiagram/Commands/ControlBinding.cs
Normal file
334
AIStudio.Wpf.ADiagram/Commands/ControlBinding.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
108
AIStudio.Wpf.ADiagram/Commands/ControlCommand.cs
Normal file
108
AIStudio.Wpf.ADiagram/Commands/ControlCommand.cs
Normal 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
|
||||
}
|
||||
140
AIStudio.Wpf.ADiagram/Commands/DelegateCommand(T).cs
Normal file
140
AIStudio.Wpf.ADiagram/Commands/DelegateCommand(T).cs
Normal 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<int?>(this.Submit, this.CanSubmit);
|
||||
/// }
|
||||
///
|
||||
/// private bool CanSubmit(int? customerId)
|
||||
/// {
|
||||
/// return (customerId.HasValue && 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
106
AIStudio.Wpf.ADiagram/Commands/DelegateCommand.cs
Normal file
106
AIStudio.Wpf.ADiagram/Commands/DelegateCommand.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
139
AIStudio.Wpf.ADiagram/Commands/DelegateCommandBase.cs
Normal file
139
AIStudio.Wpf.ADiagram/Commands/DelegateCommandBase.cs
Normal 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
|
||||
}
|
||||
}
|
||||
26
AIStudio.Wpf.ADiagram/Commands/IActiveAware.cs
Normal file
26
AIStudio.Wpf.ADiagram/Commands/IActiveAware.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
68
AIStudio.Wpf.ADiagram/Commands/PropertyObserver.cs
Normal file
68
AIStudio.Wpf.ADiagram/Commands/PropertyObserver.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
AIStudio.Wpf.ADiagram/Commands/PropertyObserverNode.cs
Normal file
70
AIStudio.Wpf.ADiagram/Commands/PropertyObserverNode.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
AIStudio.Wpf.ADiagram/Controls/AnimationHelper.cs
Normal file
98
AIStudio.Wpf.ADiagram/Controls/AnimationHelper.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
AIStudio.Wpf.ADiagram/Controls/Barcode.xaml
Normal file
23
AIStudio.Wpf.ADiagram/Controls/Barcode.xaml
Normal 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>
|
||||
129
AIStudio.Wpf.ADiagram/Controls/Barcode.xaml.cs
Normal file
129
AIStudio.Wpf.ADiagram/Controls/Barcode.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
AIStudio.Wpf.ADiagram/Controls/CancelRoutedEventArgs.cs
Normal file
18
AIStudio.Wpf.ADiagram/Controls/CancelRoutedEventArgs.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
35
AIStudio.Wpf.ADiagram/Controls/ContextMenuToggleButton.cs
Normal file
35
AIStudio.Wpf.ADiagram/Controls/ContextMenuToggleButton.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
139
AIStudio.Wpf.ADiagram/Controls/GradientStopControl.xaml
Normal file
139
AIStudio.Wpf.ADiagram/Controls/GradientStopControl.xaml
Normal 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>
|
||||
46
AIStudio.Wpf.ADiagram/Controls/GradientStopControl.xaml.cs
Normal file
46
AIStudio.Wpf.ADiagram/Controls/GradientStopControl.xaml.cs
Normal 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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
AIStudio.Wpf.ADiagram/Controls/MultiSelectComboBox.xaml
Normal file
99
AIStudio.Wpf.ADiagram/Controls/MultiSelectComboBox.xaml
Normal 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>
|
||||
334
AIStudio.Wpf.ADiagram/Controls/MultiSelectComboBox.xaml.cs
Normal file
334
AIStudio.Wpf.ADiagram/Controls/MultiSelectComboBox.xaml.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
310
AIStudio.Wpf.ADiagram/Controls/OutlineText.cs
Normal file
310
AIStudio.Wpf.ADiagram/Controls/OutlineText.cs
Normal 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
|
||||
}
|
||||
}
|
||||
34
AIStudio.Wpf.ADiagram/Controls/PopupWindow.xaml
Normal file
34
AIStudio.Wpf.ADiagram/Controls/PopupWindow.xaml
Normal 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>
|
||||
33
AIStudio.Wpf.ADiagram/Controls/PopupWindow.xaml.cs
Normal file
33
AIStudio.Wpf.ADiagram/Controls/PopupWindow.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
63
AIStudio.Wpf.ADiagram/Controls/PropertiesView.xaml
Normal file
63
AIStudio.Wpf.ADiagram/Controls/PropertiesView.xaml
Normal 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>
|
||||
228
AIStudio.Wpf.ADiagram/Controls/PropertiesView.xaml.cs
Normal file
228
AIStudio.Wpf.ADiagram/Controls/PropertiesView.xaml.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
349
AIStudio.Wpf.ADiagram/Controls/RectangleGrid.cs
Normal file
349
AIStudio.Wpf.ADiagram/Controls/RectangleGrid.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
AIStudio.Wpf.ADiagram/Controls/ScrollViewer.xaml
Normal file
58
AIStudio.Wpf.ADiagram/Controls/ScrollViewer.xaml
Normal 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>
|
||||
237
AIStudio.Wpf.ADiagram/Controls/ScrollViewer.xaml.cs
Normal file
237
AIStudio.Wpf.ADiagram/Controls/ScrollViewer.xaml.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
AIStudio.Wpf.ADiagram/Controls/SliderRotation.xaml
Normal file
38
AIStudio.Wpf.ADiagram/Controls/SliderRotation.xaml
Normal 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>
|
||||
140
AIStudio.Wpf.ADiagram/Controls/SliderRotation.xaml.cs
Normal file
140
AIStudio.Wpf.ADiagram/Controls/SliderRotation.xaml.cs
Normal 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); //计算出旋转角度
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
AIStudio.Wpf.ADiagram/Controls/TabControl.xaml
Normal file
181
AIStudio.Wpf.ADiagram/Controls/TabControl.xaml
Normal 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>
|
||||
443
AIStudio.Wpf.ADiagram/Controls/TabControl.xaml.cs
Normal file
443
AIStudio.Wpf.ADiagram/Controls/TabControl.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
467
AIStudio.Wpf.ADiagram/Controls/TabItem.cs
Normal file
467
AIStudio.Wpf.ADiagram/Controls/TabItem.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
172
AIStudio.Wpf.ADiagram/Controls/TabPanel.cs
Normal file
172
AIStudio.Wpf.ADiagram/Controls/TabPanel.cs
Normal 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
619
AIStudio.Wpf.ADiagram/Controls/WPFRuler.cs
Normal file
619
AIStudio.Wpf.ADiagram/Controls/WPFRuler.cs
Normal 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&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));
|
||||
}
|
||||
}
|
||||
}
|
||||
50
AIStudio.Wpf.ADiagram/Converters/BoolVisibilityConverter.cs
Normal file
50
AIStudio.Wpf.ADiagram/Converters/BoolVisibilityConverter.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
81
AIStudio.Wpf.ADiagram/Converters/ConverterBoolToValueMap.cs
Normal file
81
AIStudio.Wpf.ADiagram/Converters/ConverterBoolToValueMap.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
AIStudio.Wpf.ADiagram/Converters/ConverterValueMapToBool.cs
Normal file
81
AIStudio.Wpf.ADiagram/Converters/ConverterValueMapToBool.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
AIStudio.Wpf.ADiagram/Converters/CountShiftConverter.cs
Normal file
45
AIStudio.Wpf.ADiagram/Converters/CountShiftConverter.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
85
AIStudio.Wpf.ADiagram/Converters/DoubleToThickness.cs
Normal file
85
AIStudio.Wpf.ADiagram/Converters/DoubleToThickness.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
AIStudio.Wpf.ADiagram/Converters/HtmlColorConverter.cs
Normal file
50
AIStudio.Wpf.ADiagram/Converters/HtmlColorConverter.cs
Normal 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
|
||||
}
|
||||
}
|
||||
39
AIStudio.Wpf.ADiagram/Converters/IndentConverter.cs
Normal file
39
AIStudio.Wpf.ADiagram/Converters/IndentConverter.cs
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
61
AIStudio.Wpf.ADiagram/Converters/IntVisibilityConverter.cs
Normal file
61
AIStudio.Wpf.ADiagram/Converters/IntVisibilityConverter.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
AIStudio.Wpf.ADiagram/Converters/NumberConverter.cs
Normal file
25
AIStudio.Wpf.ADiagram/Converters/NumberConverter.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
36
AIStudio.Wpf.ADiagram/Converters/RulerUnitConverter.cs
Normal file
36
AIStudio.Wpf.ADiagram/Converters/RulerUnitConverter.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
AIStudio.Wpf.ADiagram/Converters/StringPathConverter.cs
Normal file
32
AIStudio.Wpf.ADiagram/Converters/StringPathConverter.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
59
AIStudio.Wpf.ADiagram/Converters/ThicknessConverter.cs
Normal file
59
AIStudio.Wpf.ADiagram/Converters/ThicknessConverter.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
AIStudio.Wpf.ADiagram/Demos/Flowchart/FlowchartService.cs
Normal file
47
AIStudio.Wpf.ADiagram/Demos/Flowchart/FlowchartService.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
AIStudio.Wpf.ADiagram/Demos/Flowchart/FlowchartViewModel.cs
Normal file
102
AIStudio.Wpf.ADiagram/Demos/Flowchart/FlowchartViewModel.cs
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
27
AIStudio.Wpf.ADiagram/Demos/Flowchart/NodeKinds.cs
Normal file
27
AIStudio.Wpf.ADiagram/Demos/Flowchart/NodeKinds.cs
Normal 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,
|
||||
}
|
||||
}
|
||||
22
AIStudio.Wpf.ADiagram/Demos/Flowchart/SelectOption.cs
Normal file
22
AIStudio.Wpf.ADiagram/Demos/Flowchart/SelectOption.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
AIStudio.Wpf.ADiagram/Demos/Flowchart/ViewModels/FlowNode.cs
Normal file
136
AIStudio.Wpf.ADiagram/Demos/Flowchart/ViewModels/FlowNode.cs
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
129
AIStudio.Wpf.ADiagram/Demos/Flowchart/ViewModels/FlowNode.xaml
Normal file
129
AIStudio.Wpf.ADiagram/Demos/Flowchart/ViewModels/FlowNode.xaml
Normal 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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
AIStudio.Wpf.ADiagram/Demos/Logical/LinkPoint.cs
Normal file
25
AIStudio.Wpf.ADiagram/Demos/Logical/LinkPoint.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
AIStudio.Wpf.ADiagram/Demos/Logical/LogicalService.cs
Normal file
23
AIStudio.Wpf.ADiagram/Demos/Logical/LogicalService.cs
Normal 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 });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
416
AIStudio.Wpf.ADiagram/Demos/Logical/LogicalViewModel.cs
Normal file
416
AIStudio.Wpf.ADiagram/Demos/Logical/LogicalViewModel.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) { }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
172
AIStudio.Wpf.ADiagram/DesignItems/Customs/1.json
Normal file
172
AIStudio.Wpf.ADiagram/DesignItems/Customs/1.json
Normal 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": [
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
15
AIStudio.Wpf.ADiagram/Enums/ColorType.cs
Normal file
15
AIStudio.Wpf.ADiagram/Enums/ColorType.cs
Normal 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
Reference in New Issue
Block a user