From 52c5065886c70f71a5a9d2b704c245696553a1cf Mon Sep 17 00:00:00 2001 From: xincheng Date: Tue, 13 May 2025 12:06:31 +0800 Subject: [PATCH] Add WPF Demo --- .gitignore | 368 ++++++++++++- WinNodeEditorTest.sln | 20 +- WpfNodeEdittorDemo/App.xaml | 9 + WpfNodeEdittorDemo/App.xaml.cs | 14 + WpfNodeEdittorDemo/AssemblyInfo.cs | 10 + WpfNodeEdittorDemo/AttrTestNode.cs | 108 ++++ .../Blender/BlenderMixColorNode.cs | 130 +++++ WpfNodeEdittorDemo/Blender/FrmEnumSelect.cs | 75 +++ WpfNodeEdittorDemo/Blender/STNodeCheckBox.cs | 48 ++ .../Blender/STNodeColorButton.cs | 31 ++ WpfNodeEdittorDemo/Blender/STNodeProgress.cs | 66 +++ WpfNodeEdittorDemo/Blender/STNodeSelectBox.cs | 55 ++ WpfNodeEdittorDemo/CalcNode.cs | 70 +++ WpfNodeEdittorDemo/EmptyOptionTestNode.cs | 20 + WpfNodeEdittorDemo/ImageNode/ImageBaseNode.cs | 41 ++ .../ImageNode/ImageChannelNode.cs | 87 +++ .../ImageNode/ImageInputNode.cs | 84 +++ WpfNodeEdittorDemo/MainWindow.xaml | 68 +++ WpfNodeEdittorDemo/MainWindow.xaml.cs | 262 +++++++++ .../NumberNode/NumberAddNode.cs | 73 +++ .../NumberNode/NumberInputNode.cs | 52 ++ WpfNodeEdittorDemo/NumberNode/NumberNode.cs | 25 + WpfNodeEdittorDemo/STNodeEditorHelper.cs | 514 ++++++++++++++++++ WpfNodeEdittorDemo/STNodeHub.cs | 32 ++ WpfNodeEdittorDemo/WpfNodeEdittorDemo.csproj | 22 + 25 files changed, 2278 insertions(+), 6 deletions(-) create mode 100644 WpfNodeEdittorDemo/App.xaml create mode 100644 WpfNodeEdittorDemo/App.xaml.cs create mode 100644 WpfNodeEdittorDemo/AssemblyInfo.cs create mode 100644 WpfNodeEdittorDemo/AttrTestNode.cs create mode 100644 WpfNodeEdittorDemo/Blender/BlenderMixColorNode.cs create mode 100644 WpfNodeEdittorDemo/Blender/FrmEnumSelect.cs create mode 100644 WpfNodeEdittorDemo/Blender/STNodeCheckBox.cs create mode 100644 WpfNodeEdittorDemo/Blender/STNodeColorButton.cs create mode 100644 WpfNodeEdittorDemo/Blender/STNodeProgress.cs create mode 100644 WpfNodeEdittorDemo/Blender/STNodeSelectBox.cs create mode 100644 WpfNodeEdittorDemo/CalcNode.cs create mode 100644 WpfNodeEdittorDemo/EmptyOptionTestNode.cs create mode 100644 WpfNodeEdittorDemo/ImageNode/ImageBaseNode.cs create mode 100644 WpfNodeEdittorDemo/ImageNode/ImageChannelNode.cs create mode 100644 WpfNodeEdittorDemo/ImageNode/ImageInputNode.cs create mode 100644 WpfNodeEdittorDemo/MainWindow.xaml create mode 100644 WpfNodeEdittorDemo/MainWindow.xaml.cs create mode 100644 WpfNodeEdittorDemo/NumberNode/NumberAddNode.cs create mode 100644 WpfNodeEdittorDemo/NumberNode/NumberInputNode.cs create mode 100644 WpfNodeEdittorDemo/NumberNode/NumberNode.cs create mode 100644 WpfNodeEdittorDemo/STNodeEditorHelper.cs create mode 100644 WpfNodeEdittorDemo/STNodeHub.cs create mode 100644 WpfNodeEdittorDemo/WpfNodeEdittorDemo.csproj diff --git a/.gitignore b/.gitignore index 4f95e2b..e37e314 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,364 @@ -.DS_Store -/Bin -bin/ -obj/ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +.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 \ No newline at end of file diff --git a/WinNodeEditorTest.sln b/WinNodeEditorTest.sln index aca14ba..846a9ee 100644 --- a/WinNodeEditorTest.sln +++ b/WinNodeEditorTest.sln @@ -1,10 +1,14 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# 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}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinNodeEditorDemo", "WinNodeEditorDemo\WinNodeEditorDemo.csproj", "{4E1829B5-2160-48F5-ABD6-11914A6A25DD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfNodeEdittorDemo", "WpfNodeEdittorDemo\WpfNodeEdittorDemo.csproj", "{B355CF99-7494-472A-8E0E-1543236FFC88}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution 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|x86.ActiveCfg = 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 GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/WpfNodeEdittorDemo/App.xaml b/WpfNodeEdittorDemo/App.xaml new file mode 100644 index 0000000..90ef0c3 --- /dev/null +++ b/WpfNodeEdittorDemo/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/WpfNodeEdittorDemo/App.xaml.cs b/WpfNodeEdittorDemo/App.xaml.cs new file mode 100644 index 0000000..d7e575d --- /dev/null +++ b/WpfNodeEdittorDemo/App.xaml.cs @@ -0,0 +1,14 @@ +using System.Configuration; +using System.Data; +using System.Windows; + +namespace WpfNodeEdittorDemo +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } + +} diff --git a/WpfNodeEdittorDemo/AssemblyInfo.cs b/WpfNodeEdittorDemo/AssemblyInfo.cs new file mode 100644 index 0000000..a8dc727 --- /dev/null +++ b/WpfNodeEdittorDemo/AssemblyInfo.cs @@ -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) +)] diff --git a/WpfNodeEdittorDemo/AttrTestNode.cs b/WpfNodeEdittorDemo/AttrTestNode.cs new file mode 100644 index 0000000..b9c7fd2 --- /dev/null +++ b/WpfNodeEdittorDemo/AttrTestNode.cs @@ -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); + } + /// + /// 此方法为魔术方法(Magic function) + /// 若存在 static void ShowHelpInfo(string) 且此类被STNodeAttribute标记 + /// 则此方法将作为属性编辑器上 查看帮助 功能 + /// + /// 此类所在的模块所在的文件路径 + 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); + } + } + /// + /// 因为属性编辑器默认并不支持Color类型数据 所以这里重写一个描述器 + /// + 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); + } + } +} diff --git a/WpfNodeEdittorDemo/Blender/BlenderMixColorNode.cs b/WpfNodeEdittorDemo/Blender/BlenderMixColorNode.cs new file mode 100644 index 0000000..8de3399 --- /dev/null +++ b/WpfNodeEdittorDemo/Blender/BlenderMixColorNode.cs @@ -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 +{ + /// + /// 此类仅仅是演示 并不包含颜色混合功能 + /// + [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); + } + } +} diff --git a/WpfNodeEdittorDemo/Blender/FrmEnumSelect.cs b/WpfNodeEdittorDemo/Blender/FrmEnumSelect.cs new file mode 100644 index 0000000..3c8e87f --- /dev/null +++ b/WpfNodeEdittorDemo/Blender/FrmEnumSelect.cs @@ -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 +{ + /// + /// 此类仅演示 作为MixRGB节点的下拉选择框弹出菜单 + /// + public class FrmEnumSelect : Form + { + private Point m_pt; + private int m_nWidth; + private float m_scale; + private List m_lst = new List(); + 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(); + } + } +} diff --git a/WpfNodeEdittorDemo/Blender/STNodeCheckBox.cs b/WpfNodeEdittorDemo/Blender/STNodeCheckBox.cs new file mode 100644 index 0000000..db3bfeb --- /dev/null +++ b/WpfNodeEdittorDemo/Blender/STNodeCheckBox.cs @@ -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 +{ + /// + /// 此类仅演示 作为MixRGB节点的复选框控件 + /// + 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); + } + } + } +} diff --git a/WpfNodeEdittorDemo/Blender/STNodeColorButton.cs b/WpfNodeEdittorDemo/Blender/STNodeColorButton.cs new file mode 100644 index 0000000..1d7aa70 --- /dev/null +++ b/WpfNodeEdittorDemo/Blender/STNodeColorButton.cs @@ -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 +{ + /// + /// 此类仅演示 作为MixRGB节点的颜色选择按钮 + /// + 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()); + } + } +} diff --git a/WpfNodeEdittorDemo/Blender/STNodeProgress.cs b/WpfNodeEdittorDemo/Blender/STNodeProgress.cs new file mode 100644 index 0000000..5fa5587 --- /dev/null +++ b/WpfNodeEdittorDemo/Blender/STNodeProgress.cs @@ -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 +{ + /// + /// 此类仅演示 作为MixRGB节点的进度条控件 + /// + 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(); + } + } +} diff --git a/WpfNodeEdittorDemo/Blender/STNodeSelectBox.cs b/WpfNodeEdittorDemo/Blender/STNodeSelectBox.cs new file mode 100644 index 0000000..9b36e87 --- /dev/null +++ b/WpfNodeEdittorDemo/Blender/STNodeSelectBox.cs @@ -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 +{ + /// + /// 此类仅演示 作为MixRGB节点的下拉框控件 + /// + 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()); + } + } +} diff --git a/WpfNodeEdittorDemo/CalcNode.cs b/WpfNodeEdittorDemo/CalcNode.cs new file mode 100644 index 0000000..01fe541 --- /dev/null +++ b/WpfNodeEdittorDemo/CalcNode.cs @@ -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 +{ + /// + /// 此节点仅演示UI自定义以及控件 并不包含功能 + /// + [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); + } + } +} diff --git a/WpfNodeEdittorDemo/EmptyOptionTestNode.cs b/WpfNodeEdittorDemo/EmptyOptionTestNode.cs new file mode 100644 index 0000000..1c0449e --- /dev/null +++ b/WpfNodeEdittorDemo/EmptyOptionTestNode.cs @@ -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); + } + } +} diff --git a/WpfNodeEdittorDemo/ImageNode/ImageBaseNode.cs b/WpfNodeEdittorDemo/ImageNode/ImageBaseNode.cs new file mode 100644 index 0000000..54010d1 --- /dev/null +++ b/WpfNodeEdittorDemo/ImageNode/ImageBaseNode.cs @@ -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 +{ + /// + /// 图片节点基类 用于确定节点风格 标题颜色 以及 数据类型颜色 + /// + public abstract class ImageBaseNode : STNode + { + /// + /// 需要作为显示绘制的图片 + /// + protected Image m_img_draw; + /// + /// 输出节点 + /// + 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); + } + } +} diff --git a/WpfNodeEdittorDemo/ImageNode/ImageChannelNode.cs b/WpfNodeEdittorDemo/ImageNode/ImageChannelNode.cs new file mode 100644 index 0000000..15fbbea --- /dev/null +++ b/WpfNodeEdittorDemo/ImageNode/ImageChannelNode.cs @@ -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); + } + } +} diff --git a/WpfNodeEdittorDemo/ImageNode/ImageInputNode.cs b/WpfNodeEdittorDemo/ImageNode/ImageInputNode.cs new file mode 100644 index 0000000..be7fb01 --- /dev/null +++ b/WpfNodeEdittorDemo/ImageNode/ImageInputNode.cs @@ -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); + } + } + /// + /// 对默认Descriptor进行扩展 使得支持文件路径选择 + /// + 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); + } + } +} diff --git a/WpfNodeEdittorDemo/MainWindow.xaml b/WpfNodeEdittorDemo/MainWindow.xaml new file mode 100644 index 0000000..8f3d94c --- /dev/null +++ b/WpfNodeEdittorDemo/MainWindow.xaml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + +