Add WPF Demo
This commit is contained in:
parent
90acc47d87
commit
52c5065886
368
.gitignore
vendored
368
.gitignore
vendored
@ -1,4 +1,364 @@
|
|||||||
.DS_Store
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
/Bin
|
## files generated by popular Visual Studio add-ons.
|
||||||
bin/
|
##
|
||||||
obj/
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
.idea/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
@ -1,10 +1,14 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2010
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.14.35906.104
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ST.Library.UI", "ST.Library.UI\ST.Library.UI.csproj", "{EFFCC270-4999-4077-A543-56CCCCE92147}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ST.Library.UI", "ST.Library.UI\ST.Library.UI.csproj", "{EFFCC270-4999-4077-A543-56CCCCE92147}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinNodeEditorDemo", "WinNodeEditorDemo\WinNodeEditorDemo.csproj", "{4E1829B5-2160-48F5-ABD6-11914A6A25DD}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinNodeEditorDemo", "WinNodeEditorDemo\WinNodeEditorDemo.csproj", "{4E1829B5-2160-48F5-ABD6-11914A6A25DD}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfNodeEdittorDemo", "WpfNodeEdittorDemo\WpfNodeEdittorDemo.csproj", "{B355CF99-7494-472A-8E0E-1543236FFC88}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -35,6 +39,18 @@ Global
|
|||||||
{4E1829B5-2160-48F5-ABD6-11914A6A25DD}.Release|Mixed Platforms.Build.0 = Release|x86
|
{4E1829B5-2160-48F5-ABD6-11914A6A25DD}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||||
{4E1829B5-2160-48F5-ABD6-11914A6A25DD}.Release|x86.ActiveCfg = Release|x86
|
{4E1829B5-2160-48F5-ABD6-11914A6A25DD}.Release|x86.ActiveCfg = Release|x86
|
||||||
{4E1829B5-2160-48F5-ABD6-11914A6A25DD}.Release|x86.Build.0 = Release|x86
|
{4E1829B5-2160-48F5-ABD6-11914A6A25DD}.Release|x86.Build.0 = Release|x86
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B355CF99-7494-472A-8E0E-1543236FFC88}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
9
WpfNodeEdittorDemo/App.xaml
Normal file
9
WpfNodeEdittorDemo/App.xaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<Application x:Class="WpfNodeEdittorDemo.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:WpfNodeEdittorDemo"
|
||||||
|
StartupUri="MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
14
WpfNodeEdittorDemo/App.xaml.cs
Normal file
14
WpfNodeEdittorDemo/App.xaml.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.Configuration;
|
||||||
|
using System.Data;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WpfNodeEdittorDemo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
WpfNodeEdittorDemo/AssemblyInfo.cs
Normal file
10
WpfNodeEdittorDemo/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)
|
||||||
|
)]
|
108
WpfNodeEdittorDemo/AttrTestNode.cs
Normal file
108
WpfNodeEdittorDemo/AttrTestNode.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo
|
||||||
|
{
|
||||||
|
[STNode("/", "Crystal_lz", "2212233137@qq.com", "www.st233.com", "关于此节点的描述信息\r\n此类为\r\nSTNodeAttribute\r\nSTNodePropertyAttribute\r\n效果演示类")]
|
||||||
|
public class AttrTestNode : STNode
|
||||||
|
{
|
||||||
|
//因为属性编辑器默认并不支持Color类型数据 所以这里重写一个描述器并指定
|
||||||
|
[STNodeProperty("颜色", "颜色信息", DescriptorType = typeof(DescriptorForColor))]
|
||||||
|
public Color Color { get; set; }
|
||||||
|
|
||||||
|
[STNodeProperty("整型数组", "整型数组测试")]
|
||||||
|
public int[] IntArr { get; set; }
|
||||||
|
|
||||||
|
[STNodeProperty("布尔", "布尔类型测试")]
|
||||||
|
public bool Bool { get; set; }
|
||||||
|
|
||||||
|
[STNodeProperty("字符串", "字符串类型测试")]
|
||||||
|
public string String { get; set; }
|
||||||
|
|
||||||
|
[STNodeProperty("整型", "整型测试")]
|
||||||
|
public int Int { get; set; }
|
||||||
|
|
||||||
|
[STNodeProperty("浮点数", "浮点数类型测试")]
|
||||||
|
public float Float { get; set; }
|
||||||
|
|
||||||
|
[STNodeProperty("枚举值", "枚举类型测试 -> FormBorderStyle")]
|
||||||
|
public FormBorderStyle STYLE { get; set; }
|
||||||
|
|
||||||
|
public AttrTestNode() {
|
||||||
|
this.String = "string";
|
||||||
|
IntArr = new int[] { 10, 20 };
|
||||||
|
base.InputOptions.Add("string", typeof(string), false);
|
||||||
|
base.OutputOptions.Add("string", typeof(string), false);
|
||||||
|
this.Title = "AttrTestNode";
|
||||||
|
this.TitleColor = Color.FromArgb(200, Color.Goldenrod);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 此方法为魔术方法(Magic function)
|
||||||
|
/// 若存在 static void ShowHelpInfo(string) 且此类被STNodeAttribute标记
|
||||||
|
/// 则此方法将作为属性编辑器上 查看帮助 功能
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="strFileName">此类所在的模块所在的文件路径</param>
|
||||||
|
public static void ShowHelpInfo(string strFileName) {
|
||||||
|
MessageBox.Show("this is -> ShowHelpInfo(string);\r\n" + strFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnOwnerChanged() {
|
||||||
|
base.OnOwnerChanged();
|
||||||
|
if (this.Owner == null) return;
|
||||||
|
this.Owner.SetTypeColor(typeof(string), Color.Goldenrod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 因为属性编辑器默认并不支持Color类型数据 所以这里重写一个描述器
|
||||||
|
/// </summary>
|
||||||
|
public class DescriptorForColor : STNodePropertyDescriptor
|
||||||
|
{
|
||||||
|
private Rectangle m_rect;//此区域用作 属性窗口上绘制颜色预览
|
||||||
|
//当此属性在属性窗口中被确定位置时候发生
|
||||||
|
protected override void OnSetItemLocation() {
|
||||||
|
base.OnSetItemLocation();
|
||||||
|
Rectangle rect = base.RectangleR;
|
||||||
|
m_rect = new Rectangle(rect.Right - 25, rect.Top + 5, 19, 12);
|
||||||
|
}
|
||||||
|
//将属性值转换为字符串 属性窗口值绘制时将采用此字符串
|
||||||
|
protected override string GetStringFromValue() {
|
||||||
|
Color clr = (Color)this.GetValue(null);
|
||||||
|
return clr.A + "," + clr.R + "," + clr.G + "," + clr.B;
|
||||||
|
}
|
||||||
|
//将属性窗口中输入的字符串转化为Color属性 当属性窗口中用户确认输入时调用
|
||||||
|
protected override object GetValueFromString(string strText) {
|
||||||
|
string[] strClr = strText.Split(',');
|
||||||
|
return Color.FromArgb(
|
||||||
|
int.Parse(strClr[0]), //A
|
||||||
|
int.Parse(strClr[1]), //R
|
||||||
|
int.Parse(strClr[2]), //G
|
||||||
|
int.Parse(strClr[3])); //B
|
||||||
|
}
|
||||||
|
//绘制属性窗口值区域时候调用
|
||||||
|
protected override void OnDrawValueRectangle(DrawingTools dt) {
|
||||||
|
base.OnDrawValueRectangle(dt);//先采用默认的绘制 并再绘制颜色预览
|
||||||
|
dt.SolidBrush.Color = (Color)this.GetValue(null);
|
||||||
|
dt.Graphics.FillRectangle(dt.SolidBrush, m_rect);//填充颜色
|
||||||
|
dt.Graphics.DrawRectangle(Pens.Black, m_rect); //绘制边框
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseClick(MouseEventArgs e) {
|
||||||
|
//如果用户点击在 颜色预览区域 则弹出系统颜色对话框
|
||||||
|
if (m_rect.Contains(e.Location)) {
|
||||||
|
ColorDialog cd = new ColorDialog();
|
||||||
|
if (cd.ShowDialog() != DialogResult.OK) return;
|
||||||
|
this.SetValue(cd.Color, null);
|
||||||
|
this.Invalidate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//否则其他区域将采用默认处理方式 弹出字符串输入框
|
||||||
|
base.OnMouseClick(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
WpfNodeEdittorDemo/Blender/BlenderMixColorNode.cs
Normal file
130
WpfNodeEdittorDemo/Blender/BlenderMixColorNode.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.Blender
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 此类仅仅是演示 并不包含颜色混合功能
|
||||||
|
/// </summary>
|
||||||
|
[STNode("/Blender/", "Crystal_lz", "2212233137@qq.com", "st233.com", "this is blender mixrgb node")]
|
||||||
|
public class BlenderMixColorNode : STNode
|
||||||
|
{
|
||||||
|
private ColorMixType _MixType;
|
||||||
|
[STNodeProperty("MixType","This is MixType")]
|
||||||
|
public ColorMixType MixType {
|
||||||
|
get { return _MixType; }
|
||||||
|
set {
|
||||||
|
_MixType = value;
|
||||||
|
m_ctrl_select.Enum = value; //当属性被赋值后 对应控件状态值也应当被修改
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _Clamp;
|
||||||
|
[STNodeProperty("Clamp","This is Clamp")]
|
||||||
|
public bool Clamp {
|
||||||
|
get { return _Clamp; }
|
||||||
|
set { _Clamp = value; m_ctrl_checkbox.Checked = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Fac = 50;
|
||||||
|
[STNodeProperty("Fac", "This is Fac")]
|
||||||
|
public int Fac {
|
||||||
|
get { return _Fac; }
|
||||||
|
set {
|
||||||
|
if (value < 0) value = 0;
|
||||||
|
if (value > 100) value = 100;
|
||||||
|
_Fac = value; m_ctrl_progess.Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _Color1 = Color.LightGray;//默认的DescriptorType不支持颜色的显示 需要扩展
|
||||||
|
[STNodeProperty("Color1", "This is color1", DescriptorType = typeof(WinNodeEditorDemo.DescriptorForColor))]
|
||||||
|
public Color Color1 {
|
||||||
|
get { return _Color1; }
|
||||||
|
set { _Color1 = value; m_ctrl_btn_1.BackColor = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _Color2 = Color.LightGray;
|
||||||
|
[STNodeProperty("Color2", "This is color2", DescriptorType = typeof(WinNodeEditorDemo.DescriptorForColor))]
|
||||||
|
public Color Color2 {
|
||||||
|
get { return _Color2; }
|
||||||
|
set { _Color2 = value; m_ctrl_btn_2.BackColor = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ColorMixType {
|
||||||
|
Mix,
|
||||||
|
Value,
|
||||||
|
Color,
|
||||||
|
Hue,
|
||||||
|
Add,
|
||||||
|
Subtract
|
||||||
|
}
|
||||||
|
|
||||||
|
private STNodeSelectEnumBox m_ctrl_select; //自定义控件
|
||||||
|
private STNodeProgress m_ctrl_progess;
|
||||||
|
private STNodeCheckBox m_ctrl_checkbox;
|
||||||
|
private STNodeColorButton m_ctrl_btn_1;
|
||||||
|
private STNodeColorButton m_ctrl_btn_2;
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.TitleColor = Color.FromArgb(200, Color.DarkKhaki);
|
||||||
|
this.Title = "MixRGB";
|
||||||
|
this.AutoSize = false;
|
||||||
|
this.Size = new Size(140, 142);
|
||||||
|
|
||||||
|
this.OutputOptions.Add("Color", typeof(Color), true);
|
||||||
|
|
||||||
|
this.InputOptions.Add(STNodeOption.Empty); //空白节点 仅站位 不参与绘制与事件触发
|
||||||
|
this.InputOptions.Add(STNodeOption.Empty);
|
||||||
|
this.InputOptions.Add(STNodeOption.Empty);
|
||||||
|
this.InputOptions.Add("", typeof(float), true);
|
||||||
|
this.InputOptions.Add("Color1", typeof(Color), true);
|
||||||
|
this.InputOptions.Add("Color2", typeof(Color), true);
|
||||||
|
|
||||||
|
m_ctrl_progess = new STNodeProgress(); //创建控件并添加到节点中
|
||||||
|
m_ctrl_progess.Text = "Fac";
|
||||||
|
m_ctrl_progess.DisplayRectangle = new Rectangle(10, 61, 120, 18);
|
||||||
|
m_ctrl_progess.ValueChanged += (s, e) => this._Fac = m_ctrl_progess.Value;
|
||||||
|
this.Controls.Add(m_ctrl_progess);
|
||||||
|
|
||||||
|
m_ctrl_checkbox = new STNodeCheckBox();
|
||||||
|
m_ctrl_checkbox.Text = "Clamp";
|
||||||
|
m_ctrl_checkbox.DisplayRectangle = new Rectangle(10, 40, 120, 20);
|
||||||
|
m_ctrl_checkbox.ValueChanged += (s, e) => this._Clamp = m_ctrl_checkbox.Checked;
|
||||||
|
this.Controls.Add(m_ctrl_checkbox);
|
||||||
|
|
||||||
|
m_ctrl_btn_1 = new STNodeColorButton();
|
||||||
|
m_ctrl_btn_1.Text = "";
|
||||||
|
m_ctrl_btn_1.BackColor = this._Color1;
|
||||||
|
m_ctrl_btn_1.DisplayRectangle = new Rectangle(80, 82, 50, 16);
|
||||||
|
m_ctrl_btn_1.ValueChanged += (s, e) => this._Color1 = m_ctrl_btn_1.BackColor;
|
||||||
|
this.Controls.Add(m_ctrl_btn_1);
|
||||||
|
|
||||||
|
m_ctrl_btn_2 = new STNodeColorButton();
|
||||||
|
m_ctrl_btn_2.Text = "";
|
||||||
|
m_ctrl_btn_2.BackColor = this._Color2;
|
||||||
|
m_ctrl_btn_2.DisplayRectangle = new Rectangle(80, 102, 50, 16);
|
||||||
|
m_ctrl_btn_2.ValueChanged += (s, e) => this._Color2 = m_ctrl_btn_2.BackColor;
|
||||||
|
this.Controls.Add(m_ctrl_btn_2);
|
||||||
|
|
||||||
|
m_ctrl_select = new STNodeSelectEnumBox();
|
||||||
|
m_ctrl_select.DisplayRectangle = new Rectangle(10, 21, 120, 18);
|
||||||
|
m_ctrl_select.Enum = this._MixType;
|
||||||
|
m_ctrl_select.ValueChanged += (s, e) => this._MixType = (ColorMixType)m_ctrl_select.Enum;
|
||||||
|
this.Controls.Add(m_ctrl_select);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnOwnerChanged() { //当控件被添加时候 向编辑器提交自己的数据类型希望显示的颜色
|
||||||
|
base.OnOwnerChanged();
|
||||||
|
if (this.Owner == null) return;
|
||||||
|
this.Owner.SetTypeColor(typeof(float), Color.Gray);
|
||||||
|
this.Owner.SetTypeColor(typeof(Color), Color.Yellow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
WpfNodeEdittorDemo/Blender/FrmEnumSelect.cs
Normal file
75
WpfNodeEdittorDemo/Blender/FrmEnumSelect.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.Blender
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 此类仅演示 作为MixRGB节点的下拉选择框弹出菜单
|
||||||
|
/// </summary>
|
||||||
|
public class FrmEnumSelect : Form
|
||||||
|
{
|
||||||
|
private Point m_pt;
|
||||||
|
private int m_nWidth;
|
||||||
|
private float m_scale;
|
||||||
|
private List<object> m_lst = new List<object>();
|
||||||
|
private StringFormat m_sf;
|
||||||
|
|
||||||
|
public Enum Enum { get; set; }
|
||||||
|
|
||||||
|
private bool m_bClosed;
|
||||||
|
|
||||||
|
public FrmEnumSelect(Enum e, Point pt, int nWidth, float scale) {
|
||||||
|
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||||
|
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||||
|
foreach (var v in Enum.GetValues(e.GetType())) m_lst.Add(v);
|
||||||
|
this.Enum = e;
|
||||||
|
m_pt = pt;
|
||||||
|
m_scale = scale;
|
||||||
|
m_nWidth = nWidth;
|
||||||
|
m_sf = new StringFormat();
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
|
||||||
|
this.ShowInTaskbar = false;
|
||||||
|
this.BackColor = Color.FromArgb(255, 34, 34, 34);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLoad(EventArgs e) {
|
||||||
|
base.OnLoad(e);
|
||||||
|
this.Location = m_pt;
|
||||||
|
this.Width = (int)(m_nWidth * m_scale);
|
||||||
|
this.Height = (int)(m_lst.Count * 20 * m_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e) {
|
||||||
|
base.OnPaint(e);
|
||||||
|
Graphics g = e.Graphics;
|
||||||
|
g.ScaleTransform(m_scale, m_scale);
|
||||||
|
Rectangle rect = new Rectangle(0, 0, this.Width, 20);
|
||||||
|
foreach (var v in m_lst) {
|
||||||
|
g.DrawString(v.ToString(), this.Font, Brushes.White, rect, m_sf);
|
||||||
|
rect.Y += rect.Height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseClick(MouseEventArgs e) {
|
||||||
|
base.OnMouseClick(e);
|
||||||
|
int nIndex = e.Y / (int)(20 * m_scale);
|
||||||
|
if (nIndex >= 0 && nIndex < m_lst.Count) this.Enum = (Enum)m_lst[nIndex];
|
||||||
|
this.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||||
|
m_bClosed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseLeave(EventArgs e) {
|
||||||
|
base.OnMouseLeave(e);
|
||||||
|
if (m_bClosed) return;
|
||||||
|
//this.DialogResult = System.Windows.Forms.DialogResult.None;
|
||||||
|
this.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
WpfNodeEdittorDemo/Blender/STNodeCheckBox.cs
Normal file
48
WpfNodeEdittorDemo/Blender/STNodeCheckBox.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.Blender
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 此类仅演示 作为MixRGB节点的复选框控件
|
||||||
|
/// </summary>
|
||||||
|
public class STNodeCheckBox : STNodeControl
|
||||||
|
{
|
||||||
|
private bool _Checked;
|
||||||
|
|
||||||
|
public bool Checked {
|
||||||
|
get { return _Checked; }
|
||||||
|
set {
|
||||||
|
_Checked = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler ValueChanged;
|
||||||
|
protected virtual void OnValueChanged(EventArgs e) {
|
||||||
|
if (this.ValueChanged != null) this.ValueChanged(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
|
||||||
|
base.OnMouseClick(e);
|
||||||
|
this.Checked = !this.Checked;
|
||||||
|
this.OnValueChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(DrawingTools dt) {
|
||||||
|
//base.OnPaint(dt);
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
g.FillRectangle(Brushes.Gray, 0, 5, 10, 10);
|
||||||
|
m_sf.Alignment = StringAlignment.Near;
|
||||||
|
g.DrawString(this.Text, this.Font, Brushes.LightGray, new Rectangle(15, 0, this.Width - 20, 20), m_sf);
|
||||||
|
if (this.Checked) {
|
||||||
|
g.FillRectangle(Brushes.Black, 2, 7, 6, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
WpfNodeEdittorDemo/Blender/STNodeColorButton.cs
Normal file
31
WpfNodeEdittorDemo/Blender/STNodeColorButton.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.Blender
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 此类仅演示 作为MixRGB节点的颜色选择按钮
|
||||||
|
/// </summary>
|
||||||
|
public class STNodeColorButton : STNodeControl
|
||||||
|
{
|
||||||
|
public event EventHandler ValueChanged;
|
||||||
|
protected virtual void OnValueChanged(EventArgs e) {
|
||||||
|
if (this.ValueChanged != null) this.ValueChanged(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
|
||||||
|
base.OnMouseClick(e);
|
||||||
|
ColorDialog cd = new ColorDialog();
|
||||||
|
if (cd.ShowDialog() != DialogResult.OK) return;
|
||||||
|
//this._Color = cd.Color;
|
||||||
|
this.BackColor = cd.Color;
|
||||||
|
this.OnValueChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
WpfNodeEdittorDemo/Blender/STNodeProgress.cs
Normal file
66
WpfNodeEdittorDemo/Blender/STNodeProgress.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.Blender
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 此类仅演示 作为MixRGB节点的进度条控件
|
||||||
|
/// </summary>
|
||||||
|
public class STNodeProgress : STNodeControl
|
||||||
|
{
|
||||||
|
private int _Value = 50;
|
||||||
|
|
||||||
|
public int Value {
|
||||||
|
get { return _Value; }
|
||||||
|
set {
|
||||||
|
_Value = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool m_bMouseDown;
|
||||||
|
|
||||||
|
public event EventHandler ValueChanged;
|
||||||
|
protected virtual void OnValueChanged(EventArgs e) {
|
||||||
|
if (this.ValueChanged != null) this.ValueChanged(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(DrawingTools dt) {
|
||||||
|
base.OnPaint(dt);
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
g.FillRectangle(Brushes.Gray, this.ClientRectangle);
|
||||||
|
g.FillRectangle(Brushes.CornflowerBlue, 0, 0, (int)((float)this._Value / 100 * this.Width), this.Height);
|
||||||
|
m_sf.Alignment = StringAlignment.Near;
|
||||||
|
g.DrawString(this.Text, this.Font, Brushes.White, this.ClientRectangle, m_sf);
|
||||||
|
m_sf.Alignment = StringAlignment.Far;
|
||||||
|
g.DrawString(((float)this._Value / 100).ToString("F2"), this.Font, Brushes.White, this.ClientRectangle, m_sf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e) {
|
||||||
|
base.OnMouseDown(e);
|
||||||
|
m_bMouseDown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e) {
|
||||||
|
base.OnMouseUp(e);
|
||||||
|
m_bMouseDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e) {
|
||||||
|
base.OnMouseMove(e);
|
||||||
|
if (!m_bMouseDown) return;
|
||||||
|
int v = (int)((float)e.X / this.Width * 100);
|
||||||
|
if (v < 0) v = 0;
|
||||||
|
if (v > 100) v = 100;
|
||||||
|
this._Value = v;
|
||||||
|
this.OnValueChanged(new EventArgs());
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
WpfNodeEdittorDemo/Blender/STNodeSelectBox.cs
Normal file
55
WpfNodeEdittorDemo/Blender/STNodeSelectBox.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.Blender
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 此类仅演示 作为MixRGB节点的下拉框控件
|
||||||
|
/// </summary>
|
||||||
|
public class STNodeSelectEnumBox : STNodeControl
|
||||||
|
{
|
||||||
|
private Enum _Enum;
|
||||||
|
public Enum Enum {
|
||||||
|
get { return _Enum; }
|
||||||
|
set {
|
||||||
|
_Enum = value;
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler ValueChanged;
|
||||||
|
protected virtual void OnValueChanged(EventArgs e) {
|
||||||
|
if (this.ValueChanged != null) this.ValueChanged(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(DrawingTools dt) {
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
dt.SolidBrush.Color = Color.FromArgb(80, 0, 0, 0);
|
||||||
|
g.FillRectangle(dt.SolidBrush, this.ClientRectangle);
|
||||||
|
m_sf.Alignment = StringAlignment.Near;
|
||||||
|
g.DrawString(this.Enum.ToString(), this.Font, Brushes.White, this.ClientRectangle, m_sf);
|
||||||
|
g.FillPolygon(Brushes.Gray, new Point[]{
|
||||||
|
new Point(this.Right - 25, 7),
|
||||||
|
new Point(this.Right - 15, 7),
|
||||||
|
new Point(this.Right - 20, 12)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
|
||||||
|
base.OnMouseClick(e);
|
||||||
|
Point pt = new Point(this.Left + this.Owner.Left, this.Top + this.Owner.Top + this.Owner.TitleHeight);
|
||||||
|
pt = this.Owner.Owner.CanvasToControl(pt);
|
||||||
|
pt = this.Owner.Owner.PointToScreen(pt);
|
||||||
|
FrmEnumSelect frm = new FrmEnumSelect(this.Enum, pt, this.Width, this.Owner.Owner.CanvasScale);
|
||||||
|
var v = frm.ShowDialog();
|
||||||
|
if (v != System.Windows.Forms.DialogResult.OK) return;
|
||||||
|
this.Enum = frm.Enum;
|
||||||
|
this.OnValueChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
WpfNodeEdittorDemo/CalcNode.cs
Normal file
70
WpfNodeEdittorDemo/CalcNode.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 此节点仅演示UI自定义以及控件 并不包含功能
|
||||||
|
/// </summary>
|
||||||
|
[STNode("/", "DebugST", "2212233137@qq.com", "st233.com", "此节点仅演示UI自定义以及控件,并不包含功能.")]
|
||||||
|
public class CalcNode : STNode
|
||||||
|
{
|
||||||
|
private StringFormat m_f;
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
m_sf = new StringFormat();
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
this.Title = "Calculator";
|
||||||
|
this.AutoSize = false; //注意需要先设置AutoSize=false 才能够进行大小设置
|
||||||
|
this.Size = new Size(218, 308);
|
||||||
|
|
||||||
|
var ctrl = new STNodeControl();
|
||||||
|
ctrl.Text = ""; //此控件为显示屏幕
|
||||||
|
ctrl.Location = new Point(13, 31);
|
||||||
|
ctrl.Size = new Size(190, 50);
|
||||||
|
this.Controls.Add(ctrl);
|
||||||
|
|
||||||
|
ctrl.Paint += (s, e) => {
|
||||||
|
m_sf.Alignment = StringAlignment.Far;
|
||||||
|
STNodeControl c = s as STNodeControl;
|
||||||
|
Graphics g = e.DrawingTools.Graphics;
|
||||||
|
g.DrawString("0", ctrl.Font, Brushes.White, c.ClientRectangle, m_sf);
|
||||||
|
};
|
||||||
|
|
||||||
|
string[] strs = { //按钮文本
|
||||||
|
"MC", "MR", "MS", "M+",
|
||||||
|
"M-", "←", "CE", "C", "+", "√",
|
||||||
|
"7", "8", "9", "/", "%",
|
||||||
|
"4", "5", "6", "*", "1/x",
|
||||||
|
"1", "2", "3", "-", "=",
|
||||||
|
"0", " ", ".", "+" };
|
||||||
|
Point p = new Point(13, 86);
|
||||||
|
for (int i = 0; i < strs.Length; i++) {
|
||||||
|
if (strs[i] == " ") continue;
|
||||||
|
ctrl = new STNodeControl();
|
||||||
|
ctrl.Text = strs[i];
|
||||||
|
ctrl.Size = new Size(34, 27);
|
||||||
|
ctrl.Left = 13 + (i % 5) * 39;
|
||||||
|
ctrl.Top = 86 + (i / 5) * 32;
|
||||||
|
if (ctrl.Text == "=") ctrl.Height = 59;
|
||||||
|
if (ctrl.Text == "0") ctrl.Width = 73;
|
||||||
|
this.Controls.Add(ctrl);
|
||||||
|
if (i == 8) ctrl.Paint += (s, e) => {
|
||||||
|
m_sf.Alignment = StringAlignment.Center;
|
||||||
|
STNodeControl c = s as STNodeControl;
|
||||||
|
Graphics g = e.DrawingTools.Graphics;
|
||||||
|
g.DrawString("_", ctrl.Font, Brushes.White, c.ClientRectangle, m_sf);
|
||||||
|
};
|
||||||
|
ctrl.MouseClick += (s, e) => System.Windows.Forms.MessageBox.Show(((STNodeControl)s).Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.OutputOptions.Add("Result", typeof(int), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
WpfNodeEdittorDemo/EmptyOptionTestNode.cs
Normal file
20
WpfNodeEdittorDemo/EmptyOptionTestNode.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo
|
||||||
|
{
|
||||||
|
[STNode("/")]
|
||||||
|
public class EmptyOptionTestNode : STNode
|
||||||
|
{
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.Title = "EmptyTest";
|
||||||
|
this.InputOptions.Add(STNodeOption.Empty);
|
||||||
|
this.InputOptions.Add("string", typeof(string), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
WpfNodeEdittorDemo/ImageNode/ImageBaseNode.cs
Normal file
41
WpfNodeEdittorDemo/ImageNode/ImageBaseNode.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.ImageNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 图片节点基类 用于确定节点风格 标题颜色 以及 数据类型颜色
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ImageBaseNode : STNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 需要作为显示绘制的图片
|
||||||
|
/// </summary>
|
||||||
|
protected Image m_img_draw;
|
||||||
|
/// <summary>
|
||||||
|
/// 输出节点
|
||||||
|
/// </summary>
|
||||||
|
protected STNodeOption m_op_img_out;
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
m_op_img_out = this.OutputOptions.Add("", typeof(Image), false);
|
||||||
|
this.AutoSize = false; //此节点需要定制UI 所以无需AutoSize
|
||||||
|
//this.Size = new Size(320,240);
|
||||||
|
this.Width = 160; //手动设置节点大小
|
||||||
|
this.Height = 120;
|
||||||
|
this.TitleColor = Color.FromArgb(200, Color.DarkCyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnOwnerChanged() { //向编辑器提交数据类型颜色
|
||||||
|
base.OnOwnerChanged();
|
||||||
|
if (this.Owner == null) return;
|
||||||
|
this.Owner.SetTypeColor(typeof(Image), Color.DarkCyan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
WpfNodeEdittorDemo/ImageNode/ImageChannelNode.cs
Normal file
87
WpfNodeEdittorDemo/ImageNode/ImageChannelNode.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.ImageNode
|
||||||
|
{
|
||||||
|
[STNode("/Image")]
|
||||||
|
public class ImageChannelNode : ImageBaseNode
|
||||||
|
{
|
||||||
|
private STNodeOption m_op_img_in; //输入的节点
|
||||||
|
private STNodeOption m_op_img_r; //R图 输出节点
|
||||||
|
private STNodeOption m_op_img_g; //G图 输出节点
|
||||||
|
private STNodeOption m_op_img_b; //B图 输出节点
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.Title = "ImageChannel";
|
||||||
|
|
||||||
|
m_op_img_in = this.InputOptions.Add("", typeof(Image), true);
|
||||||
|
m_op_img_r = this.OutputOptions.Add("R", typeof(Image), false);
|
||||||
|
m_op_img_g = this.OutputOptions.Add("G", typeof(Image), false);
|
||||||
|
m_op_img_b = this.OutputOptions.Add("B", typeof(Image), false);
|
||||||
|
//当输入节点有数据输入时候
|
||||||
|
m_op_img_in.DataTransfer += new STNodeOptionEventHandler(m_op_img_in_DataTransfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m_op_img_in_DataTransfer(object sender, STNodeOptionEventArgs e) {
|
||||||
|
//如果当前不是连接状态 或者 接受到的数据为空
|
||||||
|
if (e.Status != ConnectionStatus.Connected || e.TargetOption.Data == null) {
|
||||||
|
m_op_img_out.TransferData(null); //向所有输出节点输出空数据
|
||||||
|
m_op_img_r.TransferData(null);
|
||||||
|
m_op_img_g.TransferData(null);
|
||||||
|
m_op_img_b.TransferData(null);
|
||||||
|
m_img_draw = null; //需要绘制显示的图片置为空
|
||||||
|
} else {
|
||||||
|
Bitmap bmp = (Bitmap)e.TargetOption.Data; //否则计算图片的RGB图像
|
||||||
|
Bitmap bmp_r = new Bitmap(bmp.Width, bmp.Height);
|
||||||
|
Bitmap bmp_g = new Bitmap(bmp.Width, bmp.Height);
|
||||||
|
Bitmap bmp_b = new Bitmap(bmp.Width, bmp.Height);
|
||||||
|
BitmapData bmpData = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||||
|
BitmapData bmpData_r = bmp_r.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||||
|
BitmapData bmpData_g = bmp_g.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||||
|
BitmapData bmpData_b = bmp_b.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||||
|
byte[] byColor = new byte[bmpData.Height * bmpData.Stride];
|
||||||
|
byte[] byColor_r = new byte[byColor.Length];
|
||||||
|
byte[] byColor_g = new byte[byColor.Length];
|
||||||
|
byte[] byColor_b = new byte[byColor.Length];
|
||||||
|
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, byColor, 0, byColor.Length);
|
||||||
|
for (int y = 0; y < bmpData.Height; y++) {
|
||||||
|
int ny = y * bmpData.Stride;
|
||||||
|
for (int x = 0; x < bmpData.Width; x++) {
|
||||||
|
int nx = x << 2;
|
||||||
|
byColor_b[ny + nx] = byColor[ny + nx];
|
||||||
|
byColor_g[ny + nx + 1] = byColor[ny + nx + 1];
|
||||||
|
byColor_r[ny + nx + 2] = byColor[ny + nx + 2];
|
||||||
|
byColor_r[ny + nx + 3] = byColor_g[ny + nx + 3] = byColor_b[ny + nx + 3] = byColor[ny + nx + 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bmp.UnlockBits(bmpData);
|
||||||
|
System.Runtime.InteropServices.Marshal.Copy(byColor_r, 0, bmpData_r.Scan0, byColor_r.Length);
|
||||||
|
System.Runtime.InteropServices.Marshal.Copy(byColor_g, 0, bmpData_g.Scan0, byColor_g.Length);
|
||||||
|
System.Runtime.InteropServices.Marshal.Copy(byColor_b, 0, bmpData_b.Scan0, byColor_b.Length);
|
||||||
|
bmp_r.UnlockBits(bmpData_r);
|
||||||
|
bmp_g.UnlockBits(bmpData_g);
|
||||||
|
bmp_b.UnlockBits(bmpData_b);
|
||||||
|
m_op_img_out.TransferData(bmp); //out选项 输出原图
|
||||||
|
m_op_img_r.TransferData(bmp_r); //R选项输出R图
|
||||||
|
m_op_img_g.TransferData(bmp_g);
|
||||||
|
m_op_img_b.TransferData(bmp_b);
|
||||||
|
m_img_draw = bmp; //需要绘制显示的图片
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDrawBody(DrawingTools dt) {
|
||||||
|
base.OnDrawBody(dt);
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
Rectangle rect = new Rectangle(this.Left + 10, this.Top + 30, 120, 80);
|
||||||
|
g.FillRectangle(Brushes.Gray, rect);
|
||||||
|
if (m_img_draw != null) g.DrawImage(m_img_draw, rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
WpfNodeEdittorDemo/ImageNode/ImageInputNode.cs
Normal file
84
WpfNodeEdittorDemo/ImageNode/ImageInputNode.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.ImageNode
|
||||||
|
{
|
||||||
|
|
||||||
|
[STNode("Image", "Crystal_lz", "2212233137@qq.com", "st233.com", "Image Node")]
|
||||||
|
public class ImageInputNode : ImageBaseNode
|
||||||
|
{
|
||||||
|
private string _FileName;//默认的DescriptorType不支持文件路径的选择 所以需要扩展
|
||||||
|
[STNodeProperty("InputImage", "Click to select a image", DescriptorType = typeof(OpenFileDescriptor))]
|
||||||
|
public string FileName {
|
||||||
|
get { return _FileName; }
|
||||||
|
set {
|
||||||
|
Image img = null; //当文件名被设置时 加载图片并 向输出节点输出
|
||||||
|
if (!string.IsNullOrEmpty(value)) {
|
||||||
|
img = Image.FromFile(value);
|
||||||
|
}
|
||||||
|
if (m_img_draw != null) m_img_draw.Dispose();
|
||||||
|
m_img_draw = img;
|
||||||
|
_FileName = value;
|
||||||
|
m_op_img_out.TransferData(m_img_draw, true);
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.Title = "ImageInput";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDrawBody(DrawingTools dt) {
|
||||||
|
base.OnDrawBody(dt);
|
||||||
|
Graphics g = dt.Graphics;
|
||||||
|
Rectangle rect = new Rectangle(this.Left + 10, this.Top + 30, 140, 80);
|
||||||
|
g.FillRectangle(Brushes.Gray, rect);
|
||||||
|
if (m_img_draw != null) g.DrawImage(m_img_draw, rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 对默认Descriptor进行扩展 使得支持文件路径选择
|
||||||
|
/// </summary>
|
||||||
|
public class OpenFileDescriptor : STNodePropertyDescriptor
|
||||||
|
{
|
||||||
|
private Rectangle m_rect_open; //需要绘制"打开"按钮的区域
|
||||||
|
private StringFormat m_sf;
|
||||||
|
|
||||||
|
public OpenFileDescriptor() {
|
||||||
|
m_sf = new StringFormat();
|
||||||
|
m_sf.Alignment = StringAlignment.Center;
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnSetItemLocation() { //当在STNodePropertyGrid上确定此属性需要显示的区域时候
|
||||||
|
base.OnSetItemLocation(); //计算出"打开"按钮需要绘制的区域
|
||||||
|
m_rect_open = new Rectangle(
|
||||||
|
this.RectangleR.Right - 20,
|
||||||
|
this.RectangleR.Top,
|
||||||
|
20,
|
||||||
|
this.RectangleR.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
|
||||||
|
if (m_rect_open.Contains(e.Location)) { //点击在"打开"区域 则弹出文件选择框
|
||||||
|
OpenFileDialog ofd = new OpenFileDialog();
|
||||||
|
ofd.Filter = "*.jpg|*.jpg|*.png|*.png";
|
||||||
|
if (ofd.ShowDialog() != DialogResult.OK) return;
|
||||||
|
this.SetValue(ofd.FileName);
|
||||||
|
} else base.OnMouseClick(e); //否则默认处理方式 弹出文本输入框
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDrawValueRectangle(DrawingTools dt) {
|
||||||
|
base.OnDrawValueRectangle(dt); //在STNodePropertyGrid绘制此属性区域时候将"打开"按钮绘制上去
|
||||||
|
dt.Graphics.FillRectangle(Brushes.Gray, m_rect_open);
|
||||||
|
dt.Graphics.DrawString("+", this.Control.Font, Brushes.White, m_rect_open, m_sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
WpfNodeEdittorDemo/MainWindow.xaml
Normal file
68
WpfNodeEdittorDemo/MainWindow.xaml
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<Window x:Class="WpfNodeEdittorDemo.MainWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:WpfNodeEdittorDemo"
|
||||||
|
xmlns:st ="clr-namespace:ST.Library.UI.NodeEditor;assembly=ST.Library.UI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
PreviewKeyDown="UserControl_PreviewKeyDown"
|
||||||
|
Title="MainWindow" Height="720" Width="1280" Initialized="Window_Initialized">
|
||||||
|
<Grid x:Name="Grid1">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Margin="5" Grid.Row="0" >
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Button x:Name="ButtonOpen" Content="加载" Click="Button_Click_Open" Width="70" />
|
||||||
|
<Button x:Name="ButtonNew" Content="打开" Click="Button_Click_New" Width="70" />
|
||||||
|
<Button x:Name="ButtonClear" Content="清除" Click="Button_Click_Clear" Width="70"/>
|
||||||
|
<Button x:Name="ButtonSave" Content="保存" Click="Button_Click_Save" Width="70" Margin="0,0,10,0"/>
|
||||||
|
<Button Content="自动对齐" Click="AutoAlignment_Click" Width="70"/>
|
||||||
|
</StackPanel>
|
||||||
|
<Grid Grid.Column="2">
|
||||||
|
<Slider x:Name="ZoomSlider" Width="200" Value="{Binding STNodeEditorHelper.CanvasScale}" Maximum="3" Minimum="0.45" HorizontalAlignment="Right"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
|
<Grid Grid.Row="1">
|
||||||
|
<Grid.ColumnDefinitions >
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="300"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid >
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="300"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
<WindowsFormsHost Grid.Column="0" >
|
||||||
|
<st:STNodeEditor x:Name="STNodeEditorMain" MouseDown="STNodeEditorMain_MouseDown" MouseUp="STNodeEditorMain_MouseUp" MouseMove="STNodeEditorMain_MouseMove" MouseWheel="STNodeEditorMain_MouseWheel"/>
|
||||||
|
</WindowsFormsHost>
|
||||||
|
|
||||||
|
<Grid Grid.Column="1">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="250"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||||
|
<WindowsFormsHost Grid.Row="0">
|
||||||
|
<st:STNodeTreeView x:Name="STNodeTreeView1" />
|
||||||
|
</WindowsFormsHost>
|
||||||
|
</ScrollViewer>
|
||||||
|
<WindowsFormsHost Grid.Row="2">
|
||||||
|
<st:STNodePropertyGrid x:Name="STNodePropertyGrid1" />
|
||||||
|
</WindowsFormsHost>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
262
WpfNodeEdittorDemo/MainWindow.xaml.cs
Normal file
262
WpfNodeEdittorDemo/MainWindow.xaml.cs
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
|
||||||
|
using ColorVision.Engine.Templates.Flow;
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace WpfNodeEdittorDemo
|
||||||
|
{
|
||||||
|
public class ActionCommand
|
||||||
|
{
|
||||||
|
public string Header { get; set; }
|
||||||
|
|
||||||
|
public Action UndoAction { get; set; }
|
||||||
|
public Action RedoAction { get; set; }
|
||||||
|
|
||||||
|
public ActionCommand(Action undoAction, Action redoAction)
|
||||||
|
{
|
||||||
|
UndoAction = undoAction;
|
||||||
|
RedoAction = redoAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, (s, e) => Undo(), (s, e) => { e.CanExecute = UndoStack.Count > 0; }));
|
||||||
|
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo, (s, e) => Redo(), (s, e) => { e.CanExecute = RedoStack.Count > 0; }));
|
||||||
|
}
|
||||||
|
#region ActionCommand
|
||||||
|
|
||||||
|
public ObservableCollection<ActionCommand> UndoStack { get; set; } = new ObservableCollection<ActionCommand>();
|
||||||
|
public ObservableCollection<ActionCommand> RedoStack { get; set; } = new ObservableCollection<ActionCommand>();
|
||||||
|
|
||||||
|
public void ClearActionCommand()
|
||||||
|
{
|
||||||
|
UndoStack.Clear();
|
||||||
|
RedoStack.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddActionCommand(ActionCommand actionCommand)
|
||||||
|
{
|
||||||
|
UndoStack.Add(actionCommand);
|
||||||
|
RedoStack.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Undo()
|
||||||
|
{
|
||||||
|
if (UndoStack.Count > 0)
|
||||||
|
{
|
||||||
|
var undoAction = UndoStack[^1]; // Access the last element
|
||||||
|
UndoStack.RemoveAt(UndoStack.Count - 1); // Remove the last element
|
||||||
|
undoAction.UndoAction();
|
||||||
|
RedoStack.Add(undoAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Redo()
|
||||||
|
{
|
||||||
|
if (RedoStack.Count > 0)
|
||||||
|
{
|
||||||
|
var redoAction = RedoStack[^1]; // Access the last element
|
||||||
|
RedoStack.RemoveAt(RedoStack.Count - 1); // Remove the last element
|
||||||
|
redoAction.RedoAction();
|
||||||
|
UndoStack.Add(redoAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
private void Window_Initialized(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
STNodePropertyGrid1.Text = "Node_Property";
|
||||||
|
STNodeTreeView1.LoadAssembly( System.Windows.Forms.Application.ExecutablePath.Replace("exe","dll"));
|
||||||
|
STNodeEditorMain.LoadAssembly(System.Windows.Forms.Application.ExecutablePath.Replace("exe", "dll"));
|
||||||
|
|
||||||
|
STNodeEditorHelper STNodeEditorHelper = new STNodeEditorHelper(this, STNodeEditorMain, STNodeTreeView1, STNodePropertyGrid1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserControl_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Button_Click_Open(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
System.Windows.Forms.OpenFileDialog ofd = new();
|
||||||
|
ofd.Filter = "*.stn|*.stn";
|
||||||
|
ofd.RestoreDirectory = true;
|
||||||
|
if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
|
||||||
|
|
||||||
|
ButtonSave.Visibility = Visibility.Visible;
|
||||||
|
OpenFlow(ofd.FileName);
|
||||||
|
}
|
||||||
|
string FileFlow;
|
||||||
|
public void OpenFlow(string flowName)
|
||||||
|
{
|
||||||
|
FileFlow = flowName;
|
||||||
|
STNodeEditorMain.Nodes.Clear();
|
||||||
|
STNodeEditorMain.LoadCanvas(flowName);
|
||||||
|
Title = "流程编辑器 - " + new FileInfo(flowName).Name;
|
||||||
|
}
|
||||||
|
private bool IsMouseDown;
|
||||||
|
private System.Drawing.Point lastMousePosition;
|
||||||
|
|
||||||
|
private void STNodeEditorMain_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
|
||||||
|
{
|
||||||
|
lastMousePosition = e.Location;
|
||||||
|
System.Drawing.PointF m_pt_down_in_canvas = new System.Drawing.PointF();
|
||||||
|
m_pt_down_in_canvas.X = ((float)e.X - STNodeEditorMain.CanvasOffsetX) / STNodeEditorMain.CanvasScale;
|
||||||
|
m_pt_down_in_canvas.Y = ((float)e.Y - STNodeEditorMain.CanvasOffsetY) / STNodeEditorMain.CanvasScale;
|
||||||
|
NodeFindInfo nodeFindInfo = STNodeEditorMain.FindNodeFromPoint(m_pt_down_in_canvas);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(nodeFindInfo.Mark))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (nodeFindInfo.Node != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (nodeFindInfo.NodeOption != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
||||||
|
{
|
||||||
|
IsMouseDown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void STNodeEditorMain_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
|
||||||
|
{
|
||||||
|
IsMouseDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void STNodeEditorMain_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && IsMouseDown)
|
||||||
|
{ // 计算鼠标移动的距离
|
||||||
|
int deltaX = e.X - lastMousePosition.X;
|
||||||
|
int deltaY = e.Y - lastMousePosition.Y;
|
||||||
|
|
||||||
|
// 更新画布偏移
|
||||||
|
STNodeEditorMain.MoveCanvas(
|
||||||
|
STNodeEditorMain.CanvasOffsetX + deltaX,
|
||||||
|
STNodeEditorMain.CanvasOffsetY + deltaY,
|
||||||
|
bAnimation: false,
|
||||||
|
CanvasMoveArgs.All
|
||||||
|
);
|
||||||
|
|
||||||
|
// 更新最后的鼠标位置
|
||||||
|
lastMousePosition = e.Location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void STNodeEditorMain_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
|
||||||
|
{
|
||||||
|
var mousePosition = STNodeEditorMain.PointToClient(e.Location);
|
||||||
|
|
||||||
|
if (e.Delta < 0)
|
||||||
|
{
|
||||||
|
STNodeEditorMain.ScaleCanvas(STNodeEditorMain.CanvasScale - 0.05f, mousePosition.X, mousePosition.Y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
STNodeEditorMain.ScaleCanvas(STNodeEditorMain.CanvasScale + 0.05f, mousePosition.X, mousePosition.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Button_Click_Clear(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
FileFlow = string.Empty;
|
||||||
|
STNodeEditorMain.Nodes.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Button_Click_Save(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
private void Save()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(FileFlow) || !File.Exists(FileFlow))
|
||||||
|
{
|
||||||
|
using (System.Windows.Forms.SaveFileDialog saveFileDialog = new System.Windows.Forms.SaveFileDialog())
|
||||||
|
{
|
||||||
|
saveFileDialog.Filter = "*.stn|*.stn";
|
||||||
|
saveFileDialog.Title = "Select a File to Save";
|
||||||
|
|
||||||
|
if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
FileFlow = saveFileDialog.FileName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// User cancelled the dialog
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveToFile(FileFlow);
|
||||||
|
MessageBox.Show("保存成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveToFile(string filePath)
|
||||||
|
{
|
||||||
|
// 获取画布数据
|
||||||
|
byte[] data = STNodeEditorMain.GetCanvasData();
|
||||||
|
|
||||||
|
// 检查数据是否为空
|
||||||
|
if (data == null || data.Length == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("No data to save.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 创建文件路径的目录(如果不存在)
|
||||||
|
string directory = Path.GetDirectoryName(filePath);
|
||||||
|
if (!Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将数据写入指定文件路径
|
||||||
|
File.WriteAllBytes(filePath, data);
|
||||||
|
Console.WriteLine("File saved successfully.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"An error occurred while saving the file: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void Button_Click_New(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
System.Windows.Forms.OpenFileDialog ofd = new();
|
||||||
|
ofd.Filter = "*.stn|*.stn";
|
||||||
|
ofd.RestoreDirectory = true;
|
||||||
|
if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
|
||||||
|
OpenFlow(ofd.FileName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AutoAlignment_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
WpfNodeEdittorDemo/NumberNode/NumberAddNode.cs
Normal file
73
WpfNodeEdittorDemo/NumberNode/NumberAddNode.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.NumberNode
|
||||||
|
{
|
||||||
|
[STNode("/Number/", "Crystal_lz", "2212233137@qq.com", "www.st233.com", "This node can get two numbers add result")]
|
||||||
|
public class NumberAddNode : NumberNode
|
||||||
|
{
|
||||||
|
private STNodeOption m_in_num1;
|
||||||
|
private STNodeOption m_in_num2;
|
||||||
|
private STNodeOption m_out_num;
|
||||||
|
private int m_nNum1, m_nNum2;
|
||||||
|
private StringFormat m_sf;
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.Title = "NumberAdd";
|
||||||
|
m_sf = new StringFormat();
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
m_in_num1 = new STNodeOption("", typeof(int), true);//只能有一个连线
|
||||||
|
m_in_num2 = new STNodeOption("", typeof(int), true);//只能有一个连线
|
||||||
|
m_out_num = new STNodeOption("", typeof(int), false);//可以多个连线
|
||||||
|
this.InputOptions.Add(m_in_num1);
|
||||||
|
this.InputOptions.Add(m_in_num2);
|
||||||
|
this.OutputOptions.Add(m_out_num);
|
||||||
|
m_in_num1.DataTransfer += new STNodeOptionEventHandler(m_in_num_DataTransfer);
|
||||||
|
m_in_num2.DataTransfer += new STNodeOptionEventHandler(m_in_num_DataTransfer);
|
||||||
|
}
|
||||||
|
//当有数据传入时
|
||||||
|
void m_in_num_DataTransfer(object sender, STNodeOptionEventArgs e) {
|
||||||
|
//判断连线是否是连接状态(建立连线 断开连线 都会触发该事件)
|
||||||
|
if (e.Status == ConnectionStatus.Connected) {
|
||||||
|
if (sender == m_in_num1) {
|
||||||
|
if (e.TargetOption.Data != null) m_nNum1 = (int)e.TargetOption.Data;//TargetOption为触发此事件的Option
|
||||||
|
} else {
|
||||||
|
if (e.TargetOption.Data != null) m_nNum2 = (int)e.TargetOption.Data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sender == m_in_num1) m_nNum1 = 0; else m_nNum2 = 0;
|
||||||
|
}
|
||||||
|
//向输出选项上的所有连线传输数据 输出选项上的所有连线都会触发 DataTransfer 事件
|
||||||
|
m_out_num.TransferData(m_nNum1 + m_nNum2); //m_out_num.Data 将被自动设置
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 当绘制选项文本时候 将数字绘制 因为STNodeOption.Text被protected修饰 STNode无法进行设置
|
||||||
|
/// 因为作者并不建议对已经添加在STNode上的选项进行修改 尤其是在AutoSize被设置的情况下
|
||||||
|
/// 若有需求 应当采用其他方式 比如:重绘 或者添加STNodeControl来显示变化的文本信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt">绘制工具</param>
|
||||||
|
/// <param name="op">需要绘制的选项</param>
|
||||||
|
protected override void OnDrawOptionText(DrawingTools dt, STNodeOption op) {
|
||||||
|
base.OnDrawOptionText(dt, op);
|
||||||
|
string strText = "";
|
||||||
|
if (op == m_in_num1) {
|
||||||
|
m_sf.Alignment = StringAlignment.Near;
|
||||||
|
strText = m_nNum1.ToString();
|
||||||
|
} else if (op == m_in_num2) {
|
||||||
|
m_sf.Alignment = StringAlignment.Near;
|
||||||
|
strText = m_nNum2.ToString();
|
||||||
|
} else {
|
||||||
|
m_sf.Alignment = StringAlignment.Far;
|
||||||
|
strText = (m_nNum1 + m_nNum2).ToString();
|
||||||
|
}
|
||||||
|
dt.Graphics.DrawString(strText, this.Font, Brushes.White, op.TextRectangle, m_sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
WpfNodeEdittorDemo/NumberNode/NumberInputNode.cs
Normal file
52
WpfNodeEdittorDemo/NumberNode/NumberInputNode.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.NumberNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 此节点通过Number属性提供一个整数的输入
|
||||||
|
/// </summary>
|
||||||
|
[STNode("/Number","Crystal_lz","2212233137@qq.com","st233.com","Number input node")]
|
||||||
|
public class NumberInputNode : NumberNode
|
||||||
|
{
|
||||||
|
private int _Number;
|
||||||
|
[STNodeProperty("Input","this is input number")]
|
||||||
|
public int Number {
|
||||||
|
get { return _Number; }
|
||||||
|
set {
|
||||||
|
_Number = value;
|
||||||
|
m_op_number.TransferData(value); //将数据向下传递
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private STNodeOption m_op_number; //输出选项
|
||||||
|
private StringFormat m_sf = new StringFormat();
|
||||||
|
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.Title = "NumberInput";
|
||||||
|
m_op_number = new STNodeOption("", typeof(int), false);
|
||||||
|
this.OutputOptions.Add(m_op_number);
|
||||||
|
m_sf = new StringFormat();
|
||||||
|
m_sf.LineAlignment = StringAlignment.Center;
|
||||||
|
m_sf.Alignment = StringAlignment.Far;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 当绘制选项文本时候 将数字绘制 因为STNodeOption.Text被protected修饰 STNode无法进行设置
|
||||||
|
/// 因为作者并不建议对已经添加在STNode上的选项进行修改 尤其是在AutoSize被设置的情况下
|
||||||
|
/// 若有需求 应当采用其他方式 比如:重绘 或者添加STNodeControl来显示变化的文本信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt">绘制工具</param>
|
||||||
|
/// <param name="op">需要绘制的选项</param>
|
||||||
|
protected override void OnDrawOptionText(DrawingTools dt, STNodeOption op) {
|
||||||
|
base.OnDrawOptionText(dt, op);
|
||||||
|
dt.Graphics.DrawString(this._Number.ToString(), this.Font, Brushes.White, op.TextRectangle, m_sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
WpfNodeEdittorDemo/NumberNode/NumberNode.cs
Normal file
25
WpfNodeEdittorDemo/NumberNode/NumberNode.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo.NumberNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Number节点基类 用于确定节点风格 标题颜色 以及 数据类型颜色
|
||||||
|
/// </summary>
|
||||||
|
public abstract class NumberNode : STNode
|
||||||
|
{
|
||||||
|
protected override void OnCreate() {
|
||||||
|
base.OnCreate();
|
||||||
|
this.TitleColor = Color.FromArgb(200, Color.CornflowerBlue);
|
||||||
|
}
|
||||||
|
protected override void OnOwnerChanged() {
|
||||||
|
base.OnOwnerChanged();
|
||||||
|
if (this.Owner != null) this.Owner.SetTypeColor(typeof(int), Color.CornflowerBlue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
514
WpfNodeEdittorDemo/STNodeEditorHelper.cs
Normal file
514
WpfNodeEdittorDemo/STNodeEditorHelper.cs
Normal file
@ -0,0 +1,514 @@
|
|||||||
|
#pragma warning disable CS8603,CS8604
|
||||||
|
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Controls.Primitives;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace ColorVision.Engine.Templates.Flow
|
||||||
|
{
|
||||||
|
|
||||||
|
public class STNodeEditorHelper
|
||||||
|
{
|
||||||
|
public STNodeEditor STNodeEditor { get; set; }
|
||||||
|
|
||||||
|
public STNodePropertyGrid STNodePropertyGrid1 { get; set; }
|
||||||
|
|
||||||
|
public STNodeTreeView STNodeTreeView1 { get; set; }
|
||||||
|
|
||||||
|
public STNodeEditorHelper(Control Paraent,STNodeEditor sTNodeEditor, STNodeTreeView sTNodeTreeView1, STNodePropertyGrid sTNodePropertyGrid)
|
||||||
|
{
|
||||||
|
STNodeEditor = sTNodeEditor;
|
||||||
|
STNodeTreeView1 = sTNodeTreeView1;
|
||||||
|
STNodePropertyGrid1 = sTNodePropertyGrid;
|
||||||
|
STNodeEditor.NodeAdded += StNodeEditor1_NodeAdded;
|
||||||
|
STNodeEditor.ActiveChanged += STNodeEditorMain_ActiveChanged;
|
||||||
|
|
||||||
|
AddContentMenu();
|
||||||
|
|
||||||
|
Paraent.CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, (s, e) =>
|
||||||
|
{
|
||||||
|
foreach (var item in STNodeEditor.GetSelectedNode())
|
||||||
|
STNodeEditor.Nodes.Remove(item);
|
||||||
|
} , (s, e) => { e.CanExecute = sTNodeEditor.GetSelectedNode().Length > 0; }));
|
||||||
|
|
||||||
|
|
||||||
|
Paraent.CommandBindings.Add(new CommandBinding(ApplicationCommands.New, (s, e) => sTNodeEditor.Nodes.Clear(), (s, e) => { e.CanExecute = true; }));
|
||||||
|
|
||||||
|
Paraent.CommandBindings.Add(new CommandBinding(ApplicationCommands.Copy, (s, e) => Copy(), (s, e) => { e.CanExecute = true; }));
|
||||||
|
Paraent.CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, (s, e) => Paste(), (s, e) => { e.CanExecute = CopyNodes.Count >0;}));
|
||||||
|
Paraent.CommandBindings.Add(new CommandBinding(ApplicationCommands.SelectAll, (s, e) => SelectAll(), (s, e) => { e.CanExecute = true; }));
|
||||||
|
|
||||||
|
Paraent.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (s, e) => sTNodeEditor.Nodes.Clear(), (s, e) => { e.CanExecute = true; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<STNode> CopyNodes = new List<STNode>();
|
||||||
|
|
||||||
|
public void SelectAll()
|
||||||
|
{
|
||||||
|
foreach (var item in STNodeEditor.Nodes.OfType<STNode>())
|
||||||
|
{
|
||||||
|
STNodeEditor.AddSelectedNode(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Copy()
|
||||||
|
{
|
||||||
|
CopyNodes.Clear();
|
||||||
|
foreach (var item in STNodeEditor.GetSelectedNode())
|
||||||
|
{
|
||||||
|
CopyNodes.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Paste()
|
||||||
|
{
|
||||||
|
int offset = 10;
|
||||||
|
|
||||||
|
foreach (var item in CopyNodes)
|
||||||
|
{
|
||||||
|
Type type = item.GetType();
|
||||||
|
|
||||||
|
STNode sTNode1 = (STNode)Activator.CreateInstance(type);
|
||||||
|
if (sTNode1 != null)
|
||||||
|
{
|
||||||
|
PropertyInfo[] properties = type.GetProperties();
|
||||||
|
foreach (PropertyInfo property in properties)
|
||||||
|
{
|
||||||
|
if (property.CanRead && property.CanWrite)
|
||||||
|
{
|
||||||
|
object value = property.GetValue(item);
|
||||||
|
property.SetValue(sTNode1, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sTNode1.Left = item.Left + offset;
|
||||||
|
sTNode1.Top = item.Top + offset;
|
||||||
|
sTNode1.IsSelected = true;
|
||||||
|
STNodeEditor.Nodes.Add(sTNode1);
|
||||||
|
if (CopyNodes.Count == 1)
|
||||||
|
{
|
||||||
|
item.IsSelected = false;
|
||||||
|
STNodeEditor.RemoveSelectedNode(item);
|
||||||
|
STNodeEditor.AddSelectedNode(sTNode1);
|
||||||
|
STNodeEditor.SetActiveNode(sTNode1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
STNodeEditor.RemoveSelectedNode(item);
|
||||||
|
STNodeEditor.AddSelectedNode(sTNode1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyNodes.Clear();
|
||||||
|
foreach (var item in STNodeEditor.GetSelectedNode())
|
||||||
|
{
|
||||||
|
CopyNodes.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region Activate
|
||||||
|
private void STNodeEditorMain_ActiveChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
STNodePropertyGrid1.SetNode(STNodeEditor.ActiveNode);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ContextMenu
|
||||||
|
|
||||||
|
public void AddNodeContext()
|
||||||
|
{
|
||||||
|
foreach (var item in STNodeEditor.Nodes)
|
||||||
|
{
|
||||||
|
if (item is STNode node)
|
||||||
|
{
|
||||||
|
node.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
|
||||||
|
node.ContextMenuStrip.Items.Add("复制", null, (s, e1) => CopySTNode(node));
|
||||||
|
node.ContextMenuStrip.Items.Add("删除", null, (s, e1) => STNodeEditor.Nodes.Remove(node));
|
||||||
|
node.ContextMenuStrip.Items.Add("LockOption", null, (s, e1) => STNodeEditor.ActiveNode.LockOption = !STNodeEditor.ActiveNode.LockOption);
|
||||||
|
node.ContextMenuStrip.Items.Add("LockLocation", null, (s, e1) => STNodeEditor.ActiveNode.LockLocation = !STNodeEditor.ActiveNode.LockLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void StNodeEditor1_NodeAdded(object sender, STNodeEditorEventArgs e)
|
||||||
|
{
|
||||||
|
STNode node = e.Node;
|
||||||
|
node.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
|
||||||
|
node.ContextMenuStrip.Items.Add("删除", null, (s, e1) => STNodeEditor.Nodes.Remove(node));
|
||||||
|
node.ContextMenuStrip.Items.Add("复制", null, (s, e1) => CopySTNode(node));
|
||||||
|
node.ContextMenuStrip.Items.Add("LockOption", null, (s, e1) => STNodeEditor.ActiveNode.LockOption = !STNodeEditor.ActiveNode.LockOption);
|
||||||
|
node.ContextMenuStrip.Items.Add("LockLocation", null, (s, e1) => STNodeEditor.ActiveNode.LockLocation = !STNodeEditor.ActiveNode.LockLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopySTNode(STNode sTNode)
|
||||||
|
{
|
||||||
|
Type type = sTNode.GetType();
|
||||||
|
|
||||||
|
STNode sTNode1 = (STNode)Activator.CreateInstance(type);
|
||||||
|
if (sTNode1 != null)
|
||||||
|
{
|
||||||
|
PropertyInfo[] properties = type.GetProperties();
|
||||||
|
foreach (PropertyInfo property in properties)
|
||||||
|
{
|
||||||
|
if (property.CanRead && property.CanWrite)
|
||||||
|
{
|
||||||
|
object value = property.GetValue(sTNode);
|
||||||
|
property.SetValue(sTNode1, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sTNode1.Left = sTNode.Left;
|
||||||
|
sTNode1.Top = sTNode.Top;
|
||||||
|
|
||||||
|
STNodeEditor.Nodes.Add(sTNode1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddContentMenu()
|
||||||
|
{
|
||||||
|
STNodeEditor.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
|
||||||
|
Type STNodeTreeViewtype = STNodeTreeView1.GetType();
|
||||||
|
|
||||||
|
// 获取私有字段信息
|
||||||
|
FieldInfo fieldInfo = STNodeTreeViewtype.GetField("m_dic_all_type", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
if (fieldInfo != null)
|
||||||
|
{
|
||||||
|
// 获取字段的值
|
||||||
|
var value = fieldInfo.GetValue(STNodeTreeView1);
|
||||||
|
Dictionary<string, List<Type>> values = new Dictionary<string, List<Type>>();
|
||||||
|
if (value is Dictionary<Type, string> m_dic_all_type)
|
||||||
|
{
|
||||||
|
foreach (var item in m_dic_all_type)
|
||||||
|
{
|
||||||
|
if (values.TryGetValue(item.Value, out List<Type>? value1))
|
||||||
|
{
|
||||||
|
value1.Add(item.Key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
values.Add(item.Value, new List<Type>() { item.Key });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var nodetype in values.OrderBy(x => x.Key, Comparer<string>.Create((x, y) =>string.Compare(x,y))))
|
||||||
|
{
|
||||||
|
string header = nodetype.Key.Replace("WpfNodeEdittorDemo/", "");
|
||||||
|
var toolStripItem = new System.Windows.Forms.ToolStripMenuItem(header);
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var type in nodetype.Value)
|
||||||
|
{
|
||||||
|
if (type.IsSubclassOf(typeof(STNode)))
|
||||||
|
{
|
||||||
|
if (Activator.CreateInstance(type) is STNode sTNode)
|
||||||
|
{
|
||||||
|
toolStripItem.DropDownItems.Add(sTNode.Title, null, (s, e) =>
|
||||||
|
{
|
||||||
|
STNode sTNode1 = (STNode)Activator.CreateInstance(type);
|
||||||
|
if (sTNode1 != null)
|
||||||
|
{
|
||||||
|
var p = STNodeEditor.PointToClient(lastMousePosition);
|
||||||
|
p = STNodeEditor.ControlToCanvas(p);
|
||||||
|
sTNode1.Left = p.X;
|
||||||
|
sTNode1.Top = p.Y;
|
||||||
|
STNodeEditor.Nodes.Add(sTNode1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
STNodeEditor.ContextMenuStrip.Items.Add(toolStripItem);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STNodeEditor.ContextMenuStrip.Opening += (s, e) =>
|
||||||
|
{
|
||||||
|
if (IsOptionDisConnected) e.Cancel = true;
|
||||||
|
if (IsHover())
|
||||||
|
e.Cancel = true;
|
||||||
|
IsOptionDisConnected = false;
|
||||||
|
};
|
||||||
|
STNodeEditor.OptionDisConnected += (s, e) =>
|
||||||
|
{
|
||||||
|
IsOptionDisConnected = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
bool IsOptionDisConnected;
|
||||||
|
|
||||||
|
|
||||||
|
private System.Drawing.Point lastMousePosition;
|
||||||
|
|
||||||
|
public bool IsHover()
|
||||||
|
{
|
||||||
|
lastMousePosition = System.Windows.Forms.Cursor.Position;
|
||||||
|
var p = STNodeEditor.PointToClient(System.Windows.Forms.Cursor.Position);
|
||||||
|
p = STNodeEditor.ControlToCanvas(p);
|
||||||
|
|
||||||
|
foreach (var item in STNodeEditor.Nodes)
|
||||||
|
{
|
||||||
|
if (item is STNode sTNode)
|
||||||
|
{
|
||||||
|
bool result = sTNode.Rectangle.Contains(p);
|
||||||
|
if (result)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (sTNode.GetInputOptions() is STNodeOption[] inputOptions)
|
||||||
|
{
|
||||||
|
foreach (STNodeOption inputOption in inputOptions)
|
||||||
|
{
|
||||||
|
if (inputOption != STNodeOption.Empty && inputOption.DotRectangle.Contains(p))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sTNode.GetOutputOptions() is STNodeOption[] outputOptions)
|
||||||
|
{
|
||||||
|
foreach (STNodeOption outputOption in outputOptions)
|
||||||
|
{
|
||||||
|
if (outputOption != STNodeOption.Empty && outputOption.DotRectangle.Contains(p))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region AutoLayout
|
||||||
|
public ConnectionInfo[] ConnectionInfo { get; set; }
|
||||||
|
public float CanvasScale { get => STNodeEditor.CanvasScale; set { STNodeEditor.ScaleCanvas(value, STNodeEditor.CanvasValidBounds.X + STNodeEditor.CanvasValidBounds.Width / 2, STNodeEditor.CanvasValidBounds.Y + STNodeEditor.CanvasValidBounds.Height / 2); } }
|
||||||
|
public void AutoSize()
|
||||||
|
{
|
||||||
|
// Calculate the centers
|
||||||
|
var boundsCenterX = STNodeEditor.Bounds.Width / 2;
|
||||||
|
var boundsCenterY = STNodeEditor.Bounds.Height / 2;
|
||||||
|
|
||||||
|
// Calculate the scale factor to fit CanvasValidBounds within Bounds
|
||||||
|
var scaleX = (float)STNodeEditor.Bounds.Width / (float)STNodeEditor.CanvasValidBounds.Width;
|
||||||
|
var scaleY = (float)STNodeEditor.Bounds.Height / (float)STNodeEditor.CanvasValidBounds.Height;
|
||||||
|
CanvasScale = Math.Min(scaleX, scaleY);
|
||||||
|
CanvasScale = CanvasScale > 1 ? 1 : CanvasScale;
|
||||||
|
// Apply the scale
|
||||||
|
STNodeEditor.ScaleCanvas(CanvasScale, STNodeEditor.CanvasValidBounds.X + STNodeEditor.CanvasValidBounds.Width / 2, STNodeEditor.CanvasValidBounds.Y + STNodeEditor.CanvasValidBounds.Height / 2);
|
||||||
|
|
||||||
|
var validBoundsCenterX = STNodeEditor.CanvasValidBounds.Width / 2;
|
||||||
|
var validBoundsCenterY = STNodeEditor.CanvasValidBounds.Height / 2;
|
||||||
|
|
||||||
|
// Calculate the offsets to move CanvasValidBounds to the center of Bounds
|
||||||
|
var offsetX = boundsCenterX - validBoundsCenterX * CanvasScale - 50 * CanvasScale;
|
||||||
|
var offsetY = boundsCenterY - validBoundsCenterY * CanvasScale - 50 * CanvasScale;
|
||||||
|
|
||||||
|
|
||||||
|
// Move the canvas
|
||||||
|
STNodeEditor.MoveCanvas(offsetX, STNodeEditor.CanvasOffset.Y, bAnimation: true, CanvasMoveArgs.Left);
|
||||||
|
STNodeEditor.MoveCanvas(offsetX, offsetY, bAnimation: true, CanvasMoveArgs.Top);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyTreeLayout(int startX, int startY, int horizontalSpacing, int verticalSpacing)
|
||||||
|
{
|
||||||
|
ConnectionInfo = STNodeEditor.GetConnectionInfo();
|
||||||
|
STNode rootNode = null;
|
||||||
|
if (rootNode == null) return;
|
||||||
|
int currentY = startY;
|
||||||
|
HashSet<STNode> MoreParens = new HashSet<STNode>();
|
||||||
|
|
||||||
|
void LayoutNode(STNode node, int current)
|
||||||
|
{
|
||||||
|
int depeth = GetMaxDepth(node);
|
||||||
|
// 设置当前节点的位置
|
||||||
|
node.Left = startX + depeth * horizontalSpacing;
|
||||||
|
node.Top = current;
|
||||||
|
|
||||||
|
var parent = GetParent(node);
|
||||||
|
// 递归布局子节点
|
||||||
|
var children = GetChildren(node);
|
||||||
|
|
||||||
|
foreach (var child in children)
|
||||||
|
{
|
||||||
|
if (GetParent(child).Count > 1)
|
||||||
|
{
|
||||||
|
MoreParens.Add(child);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LayoutNode(child, currentY);
|
||||||
|
var childrenWithout1 = GetChildrenWithout(node);
|
||||||
|
if (childrenWithout1.Count > 1)
|
||||||
|
{
|
||||||
|
currentY += verticalSpacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var childrenWithout = GetChildrenWithout(node);
|
||||||
|
if (childrenWithout.Count > 1)
|
||||||
|
{
|
||||||
|
currentY = childrenWithout.Last().Top;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调整父节点位置到子节点的中心
|
||||||
|
if (childrenWithout.Count != 0)
|
||||||
|
{
|
||||||
|
int firstChildY = childrenWithout.First().Top;
|
||||||
|
int lastChildY = childrenWithout.Last().Top;
|
||||||
|
node.Top = (firstChildY + lastChildY) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.Count > 1)
|
||||||
|
{
|
||||||
|
int firstChildY = parent.First().Top;
|
||||||
|
int lastChildY = parent.Last().Top;
|
||||||
|
node.Top = (firstChildY + lastChildY) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreParentsLayoutNode(STNode node)
|
||||||
|
{
|
||||||
|
node.Left = startX + GetMaxDepth(node) * horizontalSpacing;
|
||||||
|
var parent = GetParent(node);
|
||||||
|
// 递归布局子节点
|
||||||
|
var children = GetChildren(node);
|
||||||
|
|
||||||
|
int minParentY = parent.Min(c => c.Top);
|
||||||
|
int maxParentY = parent.Max(c => c.Top);
|
||||||
|
|
||||||
|
node.Top = (minParentY + maxParentY) / 2;
|
||||||
|
|
||||||
|
SetCof(node, verticalSpacing);
|
||||||
|
int currenty = node.Top;
|
||||||
|
foreach (var child in children)
|
||||||
|
{
|
||||||
|
LayoutNode(child, currenty);
|
||||||
|
currenty += verticalSpacing;
|
||||||
|
}
|
||||||
|
MoreParens.Remove(node);
|
||||||
|
}
|
||||||
|
LayoutNode(rootNode, currentY);
|
||||||
|
while (MoreParens.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var item in MoreParens.Cast<STNode>().ToList())
|
||||||
|
{
|
||||||
|
MoreParentsLayoutNode(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCof(STNode node, int verticalSpacing)
|
||||||
|
{
|
||||||
|
foreach (var item in STNodeEditor.Nodes)
|
||||||
|
{
|
||||||
|
if (item is STNode onode)
|
||||||
|
{
|
||||||
|
if (onode != node && onode.Left == node.Left && onode.Top == node.Top)
|
||||||
|
{
|
||||||
|
onode.Top += verticalSpacing;
|
||||||
|
SetCof(node, verticalSpacing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int GetMaxDepth(STNode node)
|
||||||
|
{
|
||||||
|
var parent = GetParent(node);
|
||||||
|
if (parent.Count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return parent.Max(c => GetMaxDepth(c)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<STNode> GetParent(STNode node)
|
||||||
|
{
|
||||||
|
var list = ConnectionInfo.Where(c => c.Input.Owner == node);
|
||||||
|
List<STNode> children = new();
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
children.Add(item.Output.Owner);
|
||||||
|
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
List<STNode> GetChildrenWithout(STNode node)
|
||||||
|
{
|
||||||
|
var list = ConnectionInfo.Where(c => c.Output.Owner == node);
|
||||||
|
List<STNode> children = new();
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
if (GetParent(item.Input.Owner).Count == 1)
|
||||||
|
{
|
||||||
|
children.Add(item.Input.Owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<STNode> GetChildren(STNode node)
|
||||||
|
{
|
||||||
|
var list = ConnectionInfo.Where(c => c.Output.Owner == node);
|
||||||
|
List<STNode> children = new();
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
children.Add(item.Input.Owner);
|
||||||
|
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
private bool IsPathExists(STNode startNode, STNode endNode)
|
||||||
|
{
|
||||||
|
var visited = new HashSet<STNode>();
|
||||||
|
var queue = new Queue<STNode>();
|
||||||
|
queue.Enqueue(startNode);
|
||||||
|
|
||||||
|
while (queue.Count > 0)
|
||||||
|
{
|
||||||
|
var currentNode = queue.Dequeue();
|
||||||
|
if (currentNode == endNode)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
visited.Add(currentNode);
|
||||||
|
|
||||||
|
var children = GetChildren(currentNode);
|
||||||
|
foreach (var child in children)
|
||||||
|
{
|
||||||
|
if (!visited.Contains(child))
|
||||||
|
{
|
||||||
|
queue.Enqueue(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
32
WpfNodeEdittorDemo/STNodeHub.cs
Normal file
32
WpfNodeEdittorDemo/STNodeHub.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ST.Library.UI.NodeEditor;
|
||||||
|
|
||||||
|
namespace WinNodeEditorDemo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 类库自带的STNodeHub并未被STNodeAttribute标记 无法被STNodeTreeView显示 所以需要扩展
|
||||||
|
/// </summary>
|
||||||
|
[STNode("/", "Crystal_lz", "2212233137@qq.com", "st233.com", "This is single Hub")]
|
||||||
|
public class STNodeHubSingle : STNodeHub
|
||||||
|
{
|
||||||
|
public STNodeHubSingle()
|
||||||
|
: base(true) {
|
||||||
|
this.Title = "S_HUB";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 类库自带的STNodeHub并未被STNodeAttribute标记 无法被STNodeTreeView显示 所以需要扩展
|
||||||
|
/// </summary>
|
||||||
|
[STNode("/", "Crystal_lz", "2212233137@qq.com", "st233.com", "This multi is Hub")]
|
||||||
|
public class STNodeHubMulti : STNodeHub
|
||||||
|
{
|
||||||
|
public STNodeHubMulti()
|
||||||
|
: base(false) {
|
||||||
|
this.Title = "M_HUB";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
WpfNodeEdittorDemo/WpfNodeEdittorDemo.csproj
Normal file
22
WpfNodeEdittorDemo/WpfNodeEdittorDemo.csproj
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
<UseWindowsForms>True</UseWindowsForms>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ST.Library.UI\ST.Library.UI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Blender\FrmEnumSelect.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
x
Reference in New Issue
Block a user