├── .gitattributes
├── .gitignore
├── README.md
├── TestImages
├── 0.png
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
└── calibboard.jpg
├── VisionProcess.Controls
├── Controls
│ ├── EditableTextBlock.cs
│ ├── TabControlEx.cs
│ └── TabItemEx.cs
├── Properties
│ └── AssemblyInfo.cs
├── Selectors
│ └── EnumTemplateSelector.cs
├── Styles
│ ├── Brushes.xaml
│ ├── Controls.xaml
│ ├── Dark.xaml
│ ├── Generic.xaml
│ ├── Icons.xaml
│ └── Light.xaml
├── UserControls
│ ├── ImageEx.xaml
│ ├── ImageEx.xaml.cs
│ ├── ImageRecord.xaml
│ └── ImageRecord.xaml.cs
└── VisionProcess.Controls.csproj
├── VisionProcess.Core
├── Attributes
│ ├── DefaultToolConnectorAttribute.cs
│ ├── LocalizedDescriptionAttribute.cs
│ └── ThresholdIgnoreAttribute.cs
├── BindingProxy.cs
├── Converters
│ ├── BaseValueConverter.cs
│ ├── BooleanToBrush.cs
│ ├── BooleanToVisibilityConverter.cs
│ ├── EnumDescriptionConverter.cs
│ ├── EnumDescriptionTypeConverter.cs
│ ├── EnumToVisibilityConverter.cs
│ └── ItemToListConverter.cs
├── Extensions
│ ├── EnumBindingSourceExtension.cs
│ └── FluentSyntax.cs
├── Helpers
│ ├── AssemblyReflectionHelper.cs
│ └── PropertyReflectionHelper.cs
├── LangKeys.cs
├── Mvvm
│ └── NodifyObservableCollection.cs
├── Shapes
│ └── IVpShape.cs
├── Strings
│ ├── Strings.Designer.cs
│ ├── Strings.ar-DZ.resx
│ ├── Strings.cs-CZ.resx
│ ├── Strings.de.resx
│ ├── Strings.fr-FR.resx
│ ├── Strings.ja-Jp.resx
│ ├── Strings.pt-BR.resx
│ ├── Strings.resx
│ ├── Strings.ru-RU.resx
│ ├── Strings.uz-Latn-UZ.resx
│ ├── Strings.zh-CN.resx
│ └── Strings.zh-TW.resx
├── ToolBase
│ ├── GraphicsBase.cs
│ ├── IGraphics.cs
│ ├── IInputs.cs
│ ├── IOperator.cs
│ ├── IOutputs.cs
│ ├── InputsBase.cs
│ ├── OperatorBase.cs
│ ├── OutputsBase.cs
│ ├── Record.cs
│ └── RunStatus.cs
└── VisionProcess.Core.csproj
├── VisionProcess.Tools
├── Models
│ ├── AcquireImageOutputs.cs
│ ├── ColorConvertInputs.cs
│ ├── ColorConvertOutputs.cs
│ ├── ImageFilterInputs.cs
│ ├── ImageFilterOutputs.cs
│ ├── ImageThresholdInputs.cs
│ └── ImageThresholdOutputs.cs
├── ToolsDictionary.xaml
├── ViewModels
│ ├── AcquireImageViewModel.cs
│ ├── ColorConvertViewModel.cs
│ ├── ImageFilterViewModel.cs
│ └── ImageThresholdViewModel.cs
├── Views
│ ├── AcquireImageView.xaml
│ ├── AcquireImageView.xaml.cs
│ ├── ColorConvertView.xaml
│ ├── ColorConvertView.xaml.cs
│ ├── ImageFilterView.xaml
│ ├── ImageFilterView.xaml.cs
│ ├── ImageThresholdView.xaml
│ └── ImageThresholdView.xaml.cs
└── VisionProcess.Tools.csproj
├── VisionProcess.sln
└── VisionProcess
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── Extensions
└── OperationsExtensions.cs
├── Models
├── ConnectionModel.cs
├── ConnectorModel.cs
├── OperationGroupModel.cs
├── OperationModel.cs
├── PendingConnectionModel.cs
└── ProcessModel.cs
├── Services
├── InfoService.cs
└── WindowDialogService.cs
├── ViewModels
├── EditorViewModel.cs
├── IOConnectorViewModel.cs
├── MainViewModel.cs
└── OperationsMenuViewModel.cs
├── Views
├── EditorView.xaml
├── EditorView.xaml.cs
├── IOConnectorView.xaml
├── IOConnectorView.xaml.cs
├── MainView.xaml
├── MainView.xaml.cs
├── OperationView.xaml
├── OperationView.xaml.cs
├── OperationsMenuView.xaml
└── OperationsMenuView.xaml.cs
└── VisionProcess.csproj
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Oo]ut/
33 | [Ll]og/
34 | [Ll]ogs/
35 |
36 | # Visual Studio 2015/2017 cache/options directory
37 | .vs/
38 | # Uncomment if you have tasks that create the project's static files in wwwroot
39 | #wwwroot/
40 |
41 | # Visual Studio 2017 auto generated files
42 | Generated\ Files/
43 |
44 | # MSTest test Results
45 | [Tt]est[Rr]esult*/
46 | [Bb]uild[Ll]og.*
47 |
48 | # NUnit
49 | *.VisualState.xml
50 | TestResult.xml
51 | nunit-*.xml
52 |
53 | # Build Results of an ATL Project
54 | [Dd]ebugPS/
55 | [Rr]eleasePS/
56 | dlldata.c
57 |
58 | # Benchmark Results
59 | BenchmarkDotNet.Artifacts/
60 |
61 | # .NET Core
62 | project.lock.json
63 | project.fragment.lock.json
64 | artifacts/
65 |
66 | # ASP.NET Scaffolding
67 | ScaffoldingReadMe.txt
68 |
69 | # StyleCop
70 | StyleCopReport.xml
71 |
72 | # Files built by Visual Studio
73 | *_i.c
74 | *_p.c
75 | *_h.h
76 | *.ilk
77 | *.meta
78 | *.obj
79 | *.iobj
80 | *.pch
81 | *.pdb
82 | *.ipdb
83 | *.pgc
84 | *.pgd
85 | *.rsp
86 | *.sbr
87 | *.tlb
88 | *.tli
89 | *.tlh
90 | *.tmp
91 | *.tmp_proj
92 | *_wpftmp.csproj
93 | *.log
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio LightSwitch build output
298 | **/*.HTMLClient/GeneratedArtifacts
299 | **/*.DesktopClient/GeneratedArtifacts
300 | **/*.DesktopClient/ModelManifest.xml
301 | **/*.Server/GeneratedArtifacts
302 | **/*.Server/ModelManifest.xml
303 | _Pvt_Extensions
304 |
305 | # Paket dependency manager
306 | .paket/paket.exe
307 | paket-files/
308 |
309 | # FAKE - F# Make
310 | .fake/
311 |
312 | # CodeRush personal settings
313 | .cr/personal
314 |
315 | # Python Tools for Visual Studio (PTVS)
316 | __pycache__/
317 | *.pyc
318 |
319 | # Cake - Uncomment if you are using it
320 | # tools/**
321 | # !tools/packages.config
322 |
323 | # Tabs Studio
324 | *.tss
325 |
326 | # Telerik's JustMock configuration file
327 | *.jmconfig
328 |
329 | # BizTalk build output
330 | *.btp.cs
331 | *.btm.cs
332 | *.odx.cs
333 | *.xsd.cs
334 |
335 | # OpenCover UI analysis results
336 | OpenCover/
337 |
338 | # Azure Stream Analytics local run output
339 | ASALocalRun/
340 |
341 | # MSBuild Binary and Structured Log
342 | *.binlog
343 |
344 | # NVidia Nsight GPU debugger configuration file
345 | *.nvuser
346 |
347 | # MFractors (Xamarin productivity tool) working folder
348 | .mfractor/
349 |
350 | # Local History for Visual Studio
351 | .localhistory/
352 |
353 | # BeatPulse healthcheck temp database
354 | healthchecksdb
355 |
356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
357 | MigrationBackup/
358 |
359 | # Ionide (cross platform F# VS Code tools) working folder
360 | .ionide/
361 |
362 | # Fody - auto-generated XML schema
363 | FodyWeavers.xsd
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VisionProcess
2 |
3 | .Net 8
4 |
5 | Package :
6 | *Nodify
7 | *CommunityToolkit.Mvvm
8 | *MaterialDesignThemes.MahApps
9 | *MahApps.Metro.IconPacks
10 | *OpenCvSharp4
11 | *gong-wpf-dragdrop
12 |
13 |
14 |
15 | 
16 | 
17 |
18 |
19 | ToDo:
20 |
21 | *添加更多工具
22 | *添加 Shape ROI 图像局部处理
23 | *工具箱拖拽添加模块
24 |
--------------------------------------------------------------------------------
/TestImages/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoi102/VisionProcess/ff862f2352eba5a967232b89dd4fe5e0c251621f/TestImages/0.png
--------------------------------------------------------------------------------
/TestImages/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoi102/VisionProcess/ff862f2352eba5a967232b89dd4fe5e0c251621f/TestImages/1.png
--------------------------------------------------------------------------------
/TestImages/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoi102/VisionProcess/ff862f2352eba5a967232b89dd4fe5e0c251621f/TestImages/2.png
--------------------------------------------------------------------------------
/TestImages/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoi102/VisionProcess/ff862f2352eba5a967232b89dd4fe5e0c251621f/TestImages/3.png
--------------------------------------------------------------------------------
/TestImages/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoi102/VisionProcess/ff862f2352eba5a967232b89dd4fe5e0c251621f/TestImages/4.png
--------------------------------------------------------------------------------
/TestImages/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoi102/VisionProcess/ff862f2352eba5a967232b89dd4fe5e0c251621f/TestImages/5.png
--------------------------------------------------------------------------------
/TestImages/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoi102/VisionProcess/ff862f2352eba5a967232b89dd4fe5e0c251621f/TestImages/6.png
--------------------------------------------------------------------------------
/TestImages/calibboard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoi102/VisionProcess/ff862f2352eba5a967232b89dd4fe5e0c251621f/TestImages/calibboard.jpg
--------------------------------------------------------------------------------
/VisionProcess.Controls/Controls/EditableTextBlock.cs:
--------------------------------------------------------------------------------
1 | using Nodify;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Controls.Primitives;
5 | using System.Windows.Input;
6 |
7 | namespace VisionProcess.Controls.Controls
8 | {
9 | [TemplatePart(Name = ElementTextBox, Type = typeof(TextBox))]
10 | public class EditableTextBlock : Control
11 | {
12 | private const string ElementTextBox = "PART_TextBox";
13 |
14 | public static readonly DependencyProperty IsEditingProperty = DependencyProperty.Register(nameof(IsEditing), typeof(bool), typeof(EditableTextBlock), new FrameworkPropertyMetadata(BoxValue.False, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsEditingChanged, CoerceIsEditing));
15 | public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register(nameof(IsEditable), typeof(bool), typeof(EditableTextBlock), new FrameworkPropertyMetadata(BoxValue.True));
16 | public static readonly DependencyProperty TextProperty = TextBlock.TextProperty.AddOwner(typeof(EditableTextBlock), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
17 | public static readonly DependencyProperty AcceptsReturnProperty = TextBoxBase.AcceptsReturnProperty.AddOwner(typeof(EditableTextBlock), new FrameworkPropertyMetadata(BoxValue.False));
18 | public static readonly DependencyProperty TextWrappingProperty = TextBlock.TextWrappingProperty.AddOwner(typeof(EditableTextBlock), new FrameworkPropertyMetadata(TextWrapping.Wrap));
19 | public static readonly DependencyProperty TextTrimmingProperty = TextBlock.TextTrimmingProperty.AddOwner(typeof(EditableTextBlock), new FrameworkPropertyMetadata(TextTrimming.CharacterEllipsis));
20 | public static readonly DependencyProperty MinLinesProperty = TextBox.MinLinesProperty.AddOwner(typeof(EditableTextBlock));
21 | public static readonly DependencyProperty MaxLinesProperty = TextBox.MaxLinesProperty.AddOwner(typeof(EditableTextBlock));
22 | public static readonly DependencyProperty MaxLengthProperty = TextBox.MaxLengthProperty.AddOwner(typeof(EditableTextBlock));
23 |
24 | private static void OnIsEditingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
25 | { }
26 |
27 | private static object CoerceIsEditing(DependencyObject d, object value)
28 | {
29 | return !((EditableTextBlock)d).IsEditable ? BoxValue.False : value;
30 | }
31 |
32 | public string Text
33 | {
34 | get => (string)GetValue(TextProperty);
35 | set => SetValue(TextProperty, value);
36 | }
37 |
38 | public bool IsEditing
39 | {
40 | get => (bool)GetValue(IsEditingProperty);
41 | set => SetValue(IsEditingProperty, value);
42 | }
43 |
44 | public bool IsEditable
45 | {
46 | get => (bool)GetValue(IsEditableProperty);
47 | set => SetValue(IsEditableProperty, value);
48 | }
49 |
50 | public bool AcceptsReturn
51 | {
52 | get => (bool)GetValue(AcceptsReturnProperty);
53 | set => SetValue(AcceptsReturnProperty, value);
54 | }
55 |
56 | public int MaxLength
57 | {
58 | get => (int)GetValue(MaxLengthProperty);
59 | set => SetValue(MaxLengthProperty, value);
60 | }
61 |
62 | public int MinLines
63 | {
64 | get => (int)GetValue(MinLinesProperty);
65 | set => SetValue(MaxLinesProperty, value);
66 | }
67 |
68 | public int MaxLines
69 | {
70 | get => (int)GetValue(MaxLinesProperty);
71 | set => SetValue(MaxLinesProperty, value);
72 | }
73 |
74 | public TextWrapping TextWrapping
75 | {
76 | get => (TextWrapping)GetValue(TextWrappingProperty);
77 | set => SetValue(TextWrappingProperty, value);
78 | }
79 |
80 | public TextTrimming TextTrimming
81 | {
82 | get => (TextTrimming)GetValue(TextTrimmingProperty);
83 | set => SetValue(TextTrimmingProperty, value);
84 | }
85 |
86 | protected TextBox? TextBox { get; private set; }
87 |
88 | static EditableTextBlock()
89 | {
90 | DefaultStyleKeyProperty.OverrideMetadata(typeof(EditableTextBlock), new FrameworkPropertyMetadata(typeof(EditableTextBlock)));
91 | FocusableProperty.OverrideMetadata(typeof(EditableTextBlock), new FrameworkPropertyMetadata(BoxValue.True));
92 | }
93 |
94 | public override void OnApplyTemplate()
95 | {
96 | base.OnApplyTemplate();
97 |
98 | TextBox = GetTemplateChild(ElementTextBox) as TextBox;
99 |
100 | if (TextBox != null)
101 | {
102 | TextBox.LostFocus += OnLostFocus;
103 | TextBox.LostKeyboardFocus += OnLostFocus;
104 | TextBox.IsVisibleChanged += OnTextBoxVisiblityChanged;
105 |
106 | if (IsEditing)
107 | {
108 | TextBox.Focus();
109 | TextBox.SelectAll();
110 | }
111 | }
112 | }
113 |
114 | private void OnTextBoxVisiblityChanged(object sender, DependencyPropertyChangedEventArgs e)
115 | {
116 | if (IsEditing && TextBox != null)
117 | {
118 | if (TextBox.Focus())
119 | {
120 | TextBox.SelectAll();
121 | }
122 | else
123 | {
124 | IsEditing = false;
125 | }
126 | }
127 | }
128 |
129 | protected override void OnMouseDown(MouseButtonEventArgs e)
130 | {
131 | if (IsEditing)
132 | {
133 | e.Handled = true;
134 | }
135 | else if (IsEditable && e.ChangedButton == MouseButton.Left && e.ClickCount == 2)
136 | {
137 | IsEditing = true;
138 | e.Handled = true;
139 | }
140 | }
141 |
142 | protected override void OnMouseUp(MouseButtonEventArgs e)
143 | {
144 | if (IsEditing)
145 | {
146 | e.Handled = true;
147 | }
148 | }
149 |
150 | private void OnLostFocus(object sender, RoutedEventArgs e)
151 | {
152 | IsEditing = false;
153 | }
154 |
155 | protected override void OnKeyDown(KeyEventArgs e)
156 | {
157 | if (IsEditing && e.Key == Key.Escape || !AcceptsReturn && e.Key == Key.Enter)
158 | {
159 | IsEditing = false;
160 | }
161 |
162 | if (e.Key == Key.Enter && IsFocused && !IsEditing)
163 | {
164 | IsEditing = true;
165 | }
166 | }
167 | }
168 | }
--------------------------------------------------------------------------------
/VisionProcess.Controls/Controls/TabControlEx.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 |
5 | namespace VisionProcess.Controls.Controls
6 | {
7 | [TemplatePart(Name = ElementScrollViewer, Type = typeof(ScrollViewer))]
8 | public class TabControlEx : TabControl
9 | {
10 | private const string ElementScrollViewer = "PART_ScrollViewer";
11 |
12 | public static readonly DependencyProperty AddTabCommandProperty = DependencyProperty.Register(nameof(AddTabCommand), typeof(ICommand), typeof(TabControlEx), new PropertyMetadata(null));
13 | public static readonly DependencyProperty AutoScrollToEndProperty = DependencyProperty.Register(nameof(AutoScrollToEnd), typeof(bool), typeof(TabControlEx), new PropertyMetadata(false));
14 |
15 | public ICommand AddTabCommand
16 | {
17 | get { return (ICommand)GetValue(AddTabCommandProperty); }
18 | set { SetValue(AddTabCommandProperty, value); }
19 | }
20 |
21 | public bool AutoScrollToEnd
22 | {
23 | get { return (bool)GetValue(AutoScrollToEndProperty); }
24 | set { SetValue(AutoScrollToEndProperty, value); }
25 | }
26 |
27 | protected ScrollViewer? ScrollViewer { get; private set; }
28 |
29 | static TabControlEx()
30 | {
31 | DefaultStyleKeyProperty.OverrideMetadata(typeof(TabControlEx), new FrameworkPropertyMetadata(typeof(TabControlEx)));
32 | }
33 |
34 | public override void OnApplyTemplate()
35 | {
36 | base.OnApplyTemplate();
37 |
38 | ScrollViewer = GetTemplateChild(ElementScrollViewer) as ScrollViewer;
39 | if (ScrollViewer != null)
40 | {
41 | ScrollViewer.ScrollChanged += OnScrollChanged;
42 | }
43 | }
44 |
45 | private void OnScrollChanged(object sender, ScrollChangedEventArgs e)
46 | {
47 | if (e.ExtentWidthChange > 0 && e.ViewportWidth < e.ExtentWidth && AutoScrollToEnd)
48 | {
49 | ScrollViewer?.ScrollToRightEnd();
50 | }
51 | }
52 |
53 | protected override DependencyObject GetContainerForItemOverride()
54 | {
55 | return new TabItemEx();
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/VisionProcess.Controls/Controls/TabItemEx.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 |
5 | namespace VisionProcess.Controls.Controls
6 | {
7 | public class TabItemEx : TabItem
8 | {
9 | public static readonly DependencyProperty CloseTabCommandProperty = DependencyProperty.Register(nameof(CloseTabCommand), typeof(ICommand), typeof(TabItemEx), new PropertyMetadata(null));
10 | public static readonly DependencyProperty CloseTabCommandParameterProperty = DependencyProperty.Register(nameof(CloseTabCommandParameter), typeof(object), typeof(TabItemEx), new PropertyMetadata(null));
11 |
12 | public ICommand CloseTabCommand
13 | {
14 | get { return (ICommand)GetValue(CloseTabCommandProperty); }
15 | set { SetValue(CloseTabCommandProperty, value); }
16 | }
17 |
18 | public object CloseTabCommandParameter
19 | {
20 | get { return GetValue(CloseTabCommandParameterProperty); }
21 | set { SetValue(CloseTabCommandParameterProperty, value); }
22 | }
23 |
24 | static TabItemEx()
25 | {
26 | DefaultStyleKeyProperty.OverrideMetadata(typeof(TabItemEx), new FrameworkPropertyMetadata(typeof(TabItemEx)));
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/VisionProcess.Controls/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Markup;
3 |
4 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
5 | [assembly: XmlnsPrefix(@"https://github.com/yoi102/xaml/controls", "yr")]
6 | [assembly: XmlnsDefinition(@"https://github.com/yoi102/xaml/controls", "VisionProcess.Controls.Controls")]
7 | [assembly: XmlnsDefinition(@"https://github.com/yoi102/xaml/controls", "VisionProcess.Controls.UserControls")]
--------------------------------------------------------------------------------
/VisionProcess.Controls/Selectors/EnumTemplateSelector.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | namespace VisionProcess.Controls.Selectors
5 | {
6 | public class EnumTemplateSelector : DataTemplateSelector
7 | {
8 | public override DataTemplate? SelectTemplate(object item, DependencyObject container)
9 | {
10 | if (container is FrameworkElement element)
11 | {
12 | if (item.GetType().IsEnum)
13 | {
14 | return element.FindResource(item.ToString()) as DataTemplate;
15 | }
16 | }
17 | return null;
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/VisionProcess.Controls/Styles/Brushes.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
15 |
16 |
20 |
21 |
25 |
26 |
30 |
31 |
35 |
36 |
40 |
41 |
45 |
46 |
50 |
51 |
55 |
--------------------------------------------------------------------------------
/VisionProcess.Controls/Styles/Dark.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | White
6 | Gray
7 |
8 | #333337
9 | #1B1B1C
10 | #3F3F46
11 |
12 | #3F3F3F
13 | Gray
14 | #7EB4EA
15 | #569DE5
16 |
17 | #333337
18 |
19 |
--------------------------------------------------------------------------------
/VisionProcess.Controls/Styles/Light.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Black
6 | Gray
7 |
8 | #D4DCF2
9 | #CCD6ED
10 | #B1C5FF
11 |
12 | #CBCCDF
13 | Gray
14 | #7EB4EA
15 | #569DE5
16 |
17 | #7EB4EA
18 |
19 |
--------------------------------------------------------------------------------
/VisionProcess.Controls/UserControls/ImageEx.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
28 |
29 |
30 |
34 |
38 |
43 |
44 |
45 |
46 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
70 |
71 |
75 |
76 |
77 |
81 |
82 |
87 |
88 |
89 |
90 |
94 |
95 |
100 |
101 |
106 |
107 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/VisionProcess.Controls/UserControls/ImageRecord.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
22 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/VisionProcess.Controls/UserControls/ImageRecord.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using VisionProcess.Core.ToolBase;
4 |
5 | namespace VisionProcess.Controls.UserControls
6 | {
7 | ///
8 | /// ImageRecord.xaml 的交互逻辑
9 | ///
10 | public partial class ImageRecord : UserControl
11 | {
12 | public ImageRecord()
13 | {
14 | InitializeComponent();
15 | }
16 |
17 | public static readonly DependencyProperty RecordSourceProperty =
18 | DependencyProperty.Register(
19 | nameof(RecordSource),
20 | typeof(ICollection),
21 | typeof(ImageRecord),
22 | new PropertyMetadata(null, RecordSourcePropertyChanged));
23 |
24 | public static readonly DependencyProperty SelectedRecordProperty =
25 | DependencyProperty.Register(
26 | nameof(SelectedRecord),
27 | typeof(Record),
28 | typeof(ImageRecord),
29 | new PropertyMetadata(null, SelectedRecordRecordChanged));
30 |
31 | public ICollection? RecordSource
32 | {
33 | get { return (ICollection)GetValue(RecordSourceProperty); }
34 | set { SetValue(RecordSourceProperty, value); }
35 | }
36 |
37 | public Record? SelectedRecord
38 | {
39 | get { return (Record)GetValue(SelectedRecordProperty); }
40 | set { SetValue(SelectedRecordProperty, value); }
41 | }
42 |
43 | private static void RecordSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
44 | {
45 | var imageRecord = (ImageRecord)d;
46 | if (e.NewValue is not null)
47 | {
48 | imageRecord.SelectedRecord = ((ICollection)e.NewValue).FirstOrDefault();//默认选项
49 | //这里需要通知前台
50 | }
51 | }
52 |
53 | private static void SelectedRecordRecordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
54 | {
55 | //ImageRecord ImageRecord = (ImageRecord)d;
56 | //if (e.NewValue is not null)
57 | //{
58 | // ImageRecord.image.ImageSource = ((Record)e.NewValue).DisplayImage!;
59 | //}
60 | //else
61 | //{
62 | // ImageRecord.image.ImageSource = null;
63 | //}
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/VisionProcess.Controls/VisionProcess.Controls.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0-windows
5 | enable
6 | true
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Code
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/VisionProcess.Core/Attributes/DefaultToolConnectorAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace VisionProcess.Core.Attributes
2 | {
3 | [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
4 | public class DefaultToolConnectorAttribute : Attribute
5 | {
6 | public DefaultToolConnectorAttribute(bool isInput, string title, string path)
7 | {
8 | IsInput = isInput;
9 | Title = title;
10 | Path = path;
11 | }
12 |
13 | public bool IsInput { get; }
14 | public string Title { get; }
15 | public string Path { get; }
16 | }
17 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Attributes/LocalizedDescriptionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Resources;
3 |
4 | namespace VisionProcess.Core.Attributes
5 | {
6 | public class LocalizedDescriptionAttribute : DescriptionAttribute
7 | {
8 | private ResourceManager resourceManager;
9 | private string resourceKey;
10 |
11 | public LocalizedDescriptionAttribute(string resourceKey, Type resourceType)
12 | {
13 | resourceManager = new ResourceManager(resourceType);
14 | this.resourceKey = resourceKey;
15 | }
16 |
17 | public override string Description
18 | {
19 | get
20 | {
21 | string? description = resourceManager.GetString(resourceKey);
22 | return string.IsNullOrWhiteSpace(description) ? string.Format("[[{0}]]", resourceKey) : description;
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Attributes/ThresholdIgnoreAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace VisionProcess.Core.Attributes
2 | {
3 | [System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
4 | public sealed class ThresholdIgnoreAttribute : Attribute
5 | { }
6 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/BindingProxy.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace VisionProcess.Core
4 | {
5 | public class BindingProxy : Freezable
6 | {
7 | public static readonly DependencyProperty DataContextProperty = DependencyProperty.Register(
8 | nameof(DataContext),
9 | typeof(object),
10 | typeof(BindingProxy),
11 | new UIPropertyMetadata(default(object)));
12 |
13 | public object DataContext
14 | {
15 | get => GetValue(DataContextProperty);
16 | set => SetValue(DataContextProperty, value);
17 | }
18 |
19 | protected override Freezable CreateInstanceCore()
20 | => new BindingProxy();
21 | }
22 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Converters/BaseValueConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Windows.Data;
3 | using System.Windows.Markup;
4 |
5 | namespace VisionProcess.Core.Converters
6 | {
7 | public abstract class BaseValueConverter : MarkupExtension, IValueConverter
8 | {
9 | public abstract object? Convert(object value, Type targetType, object parameter, CultureInfo culture);
10 |
11 | public abstract object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
12 |
13 | public override object ProvideValue(IServiceProvider serviceProvider)
14 | {
15 | return this;
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Converters/BooleanToBrush.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Windows.Data;
3 | using System.Windows.Media;
4 |
5 | namespace VisionProcess.Core.Converters
6 | {
7 | public class BooleanToBrush : BaseValueConverter
8 | {
9 | public Brush TrueValue { get; set; } = Brushes.Lime;
10 | public Brush FalseValue { get; set; } = Brushes.Red;
11 |
12 | public override object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
13 | {
14 | return value is bool b ? b ? TrueValue : FalseValue : Binding.DoNothing;
15 | }
16 |
17 | public override object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
18 | {
19 | return Binding.DoNothing;
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Converters/BooleanToVisibilityConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Windows;
3 | using System.Windows.Data;
4 |
5 | namespace VisionProcess.Core.Converters
6 | {
7 | public class BooleanToVisibilityConverter : BaseValueConverter
8 | {
9 | public bool UseHidden { get; set; }
10 | public bool Reversed { get; set; }
11 |
12 | public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
13 | {
14 | if (value is bool b)
15 | {
16 | if (Reversed) b = !b;
17 | return b ? Visibility.Visible : (object)(UseHidden ? Visibility.Hidden : Visibility.Collapsed);
18 | }
19 | else
20 | return Binding.DoNothing;
21 | }
22 |
23 | public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
24 | {
25 | return Binding.DoNothing;
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Converters/EnumDescriptionConverter.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 | using System.Windows;
5 |
6 | namespace VisionProcess.Core.Converters
7 | {
8 |
9 | public class EnumDescriptionConverter : IValueConverter
10 | {
11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | if (value == null)
14 | return DependencyProperty.UnsetValue;
15 |
16 | return GetEnumDescription(value);
17 | }
18 |
19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
20 | {
21 | return string.Empty;
22 | }
23 |
24 | private string GetEnumDescription(object enumObject)
25 | {
26 | var fieldInfo = enumObject.GetType().GetField(enumObject.ToString());
27 |
28 | DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo!.GetCustomAttributes(typeof(DescriptionAttribute), false);
29 |
30 | if (attributes != null && attributes.Length > 0)
31 | return attributes[0].Description;
32 | else
33 | return enumObject.ToString();
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Converters/EnumDescriptionTypeConverter.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Reflection;
3 |
4 | namespace VisionProcess.Core.Converters
5 | {
6 | public class EnumDescriptionTypeConverter(Type type) : EnumConverter(type)
7 | {
8 | public override object? ConvertTo(ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object? value, Type destinationType)
9 | {
10 | if (destinationType == typeof(string))
11 | {
12 | if (value != null)
13 | {
14 | FieldInfo? fi = value.GetType().GetField(value.ToString()!);
15 | if (fi != null)
16 | {
17 | //var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
18 | //return ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) ? attributes[0].Description : value.ToString();
19 |
20 | var attributes = (DescriptionAttribute?)fi.GetCustomAttribute(typeof(DescriptionAttribute), false);
21 | return ((attributes is not null) && (!String.IsNullOrEmpty(attributes.Description))) ? attributes.Description : value.ToString();
22 | }
23 | }
24 |
25 | return string.Empty;
26 | }
27 |
28 | return base.ConvertTo(context, culture, value, destinationType);
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Converters/EnumToVisibilityConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Windows;
3 | using System.Windows.Data;
4 |
5 | namespace VisionProcess.Core.Converters
6 | {
7 | public class EnumToVisibilityConverter : BaseValueConverter
8 | {
9 | public bool UseHidden { get; set; }
10 | public int VisibleValue { get; set; }
11 | //public params int[] VisibleValues { get; set; }
12 |
13 | public override object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
14 | {
15 | var type = value.GetType();
16 | if (type.IsEnum)
17 | {
18 | var v = (int)value;
19 |
20 | return v == VisibleValue ? Visibility.Visible : (object)(UseHidden ? Visibility.Hidden : Visibility.Collapsed);
21 | }
22 | return Binding.DoNothing;
23 | }
24 |
25 | public override object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
26 | {
27 | throw new NotImplementedException();
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Converters/ItemToListConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Globalization;
3 |
4 | namespace VisionProcess.Core.Converters
5 | {
6 | public class ItemToListConverter : BaseValueConverter
7 | {
8 | public override object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
9 | {
10 | if (value != null)
11 | {
12 | var argType = value.GetType();
13 | var listType = typeof(List<>).MakeGenericType(argType);
14 | var list = Activator.CreateInstance(listType) as IList;
15 | list?.Add(value);
16 |
17 | return list;
18 | }
19 |
20 | return value;
21 | }
22 |
23 | public override object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
24 | {
25 | throw new NotSupportedException();
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Extensions/EnumBindingSourceExtension.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Markup;
2 |
3 | namespace VisionProcess.Core.Extensions
4 | {
5 | ///
6 | /// 用于 combobox 枚举源的绑定
7 | ///
8 | public class EnumBindingSourceExtension : MarkupExtension
9 | {
10 | private Type? enumType;
11 |
12 | public Type? EnumType
13 | {
14 | get
15 | {
16 | return enumType;
17 | }
18 | set
19 | {
20 | if (value != enumType)
21 | {
22 | if (null != value)
23 | {
24 | Type enumType = Nullable.GetUnderlyingType(value) ?? value;
25 |
26 | if (!enumType.IsEnum)
27 | throw new ArgumentException("Type must be for an Enum.");
28 | }
29 |
30 | enumType = value;
31 | }
32 | }
33 | }
34 |
35 | public EnumBindingSourceExtension()
36 | { }
37 |
38 | public EnumBindingSourceExtension(Type enumType)
39 | {
40 | EnumType = enumType;
41 | }
42 |
43 | public override object ProvideValue(IServiceProvider serviceProvider)
44 | {
45 | if (null == enumType)
46 | throw new InvalidOperationException("The EnumType must be specified.");
47 |
48 | Type actualEnumType = Nullable.GetUnderlyingType(enumType) ?? enumType;
49 | Array enumValues = Enum.GetValues(actualEnumType);
50 |
51 | if (actualEnumType == enumType)
52 | return enumValues;
53 |
54 | Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1);
55 | enumValues.CopyTo(tempArray, 1);
56 | return tempArray;
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Extensions/FluentSyntax.cs:
--------------------------------------------------------------------------------
1 | namespace VisionProcess.Core.Extensions
2 | {
3 | public static class FluentSyntax
4 | {
5 | public static void Then(this T caller, Action action)
6 | => action?.Invoke(caller);
7 |
8 | public static bool Then(this bool condition, Action action)
9 | {
10 | if (condition)
11 | {
12 | action();
13 | }
14 |
15 | return condition;
16 | }
17 |
18 | public static bool Else(this bool condition, Action action)
19 | {
20 | if (!condition)
21 | {
22 | action();
23 | }
24 |
25 | return condition;
26 | }
27 |
28 | public static IEnumerable ForEach(this IEnumerable collection, Action action)
29 | {
30 | if (collection is IList list)
31 | {
32 | for (int i = 0; i < list.Count; i++)
33 | {
34 | action(list[i]);
35 | }
36 | }
37 | else
38 | {
39 | foreach (var item in collection)
40 | {
41 | action(item);
42 | }
43 | }
44 |
45 | return collection;
46 | }
47 |
48 | public static ICollection AddRange(this ICollection collection, IEnumerable values)
49 | {
50 | values.ForEach(collection.Add);
51 | return collection;
52 | }
53 |
54 | public static ICollection RemoveRange(this ICollection collection, IEnumerable values)
55 | {
56 | values.ForEach(v => collection.Remove(v));
57 | return collection;
58 | }
59 |
60 | public static ICollection RemoveOne(this ICollection collection, Func search)
61 | {
62 | if (collection.FirstOrDefault(search) is { } x)
63 | {
64 | collection.Remove(x);
65 | }
66 |
67 | return collection;
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Helpers/AssemblyReflectionHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Diagnostics.CodeAnalysis;
3 | using System.IO;
4 | using System.Reflection;
5 | using System.Reflection.Metadata;
6 | using System.Reflection.PortableExecutable;
7 |
8 | namespace VisionProcess.Core.Helpers;
9 |
10 | public static class AssemblyReflectionHelper
11 | {
12 | ///
13 | /// 据产品名称获取程序集
14 | ///
15 | ///
16 | ///
17 | public static IEnumerable GetAssembliesByProductName(string productName)
18 | {
19 | var assemblies = AppDomain.CurrentDomain.GetAssemblies();
20 | foreach (var asm in assemblies)
21 | {
22 | var asmCompanyAttr = asm.GetCustomAttribute();
23 | if (asmCompanyAttr != null && asmCompanyAttr.Product == productName)
24 | {
25 | yield return asm;
26 | }
27 | }
28 | }
29 |
30 | //是否是微软等的官方Assembly
31 | private static bool IsSystemAssembly(Assembly asm)
32 | {
33 | var asmCompanyAttr = asm.GetCustomAttribute();
34 | if (asmCompanyAttr == null)
35 | {
36 | return false;
37 | }
38 | else
39 | {
40 | string companyName = asmCompanyAttr.Company;
41 | return companyName.Contains("Microsoft");
42 | }
43 | }
44 |
45 | private static bool IsSystemAssembly(string asmPath)
46 | {
47 | var moduleDef = AsmResolver.DotNet.ModuleDefinition.FromFile(asmPath);
48 | var assembly = moduleDef.Assembly;
49 | if (assembly == null)
50 | {
51 | return false;
52 | }
53 | var asmCompanyAttr = assembly.CustomAttributes.FirstOrDefault(c => c.Constructor?.DeclaringType?.FullName == typeof(AssemblyCompanyAttribute).FullName);
54 | if (asmCompanyAttr == null)
55 | {
56 | return false;
57 | }
58 | var companyName = ((AsmResolver.Utf8String?)asmCompanyAttr.Signature?.FixedArguments[0]?.Element)?.Value;
59 | if (companyName == null)
60 | {
61 | return false;
62 | }
63 | return companyName.Contains("Microsoft");
64 | }
65 |
66 | ///
67 | /// 判断 file 这个文件是否是程序集
68 | ///
69 | ///
70 | ///
71 | private static bool IsManagedAssembly(string file)
72 | {
73 | using var fs = File.OpenRead(file);
74 | using PEReader peReader = new PEReader(fs);
75 | return peReader.HasMetadata && peReader.GetMetadataReader().IsAssembly;
76 | }
77 |
78 | private static Assembly? TryLoadAssembly(string asmPath)
79 | {
80 | AssemblyName asmName = AssemblyName.GetAssemblyName(asmPath);
81 | Assembly? asm = null;
82 | try
83 | {
84 | asm = Assembly.Load(asmName);
85 | }
86 | catch (BadImageFormatException ex)
87 | {
88 | Debug.WriteLine(ex);
89 | }
90 | catch (FileLoadException ex)
91 | {
92 | Debug.WriteLine(ex);
93 | }
94 | catch (FileNotFoundException ex)
95 | {
96 | Debug.WriteLine(ex);
97 | }
98 |
99 | if (asm == null)
100 | {
101 | try
102 | {
103 | asm = Assembly.LoadFile(asmPath);
104 | }
105 | catch (BadImageFormatException ex)
106 | {
107 | Debug.WriteLine(ex);
108 | }
109 | catch (FileLoadException ex)
110 | {
111 | Debug.WriteLine(ex);
112 | }
113 | }
114 | return asm;
115 | }
116 |
117 | ///
118 | /// loop through all assemblies
119 | ///
120 | ///
121 | public static IEnumerable GetAllReferencedAssemblies(bool skipSystemAssemblies = true)
122 | {
123 | Assembly? rootAssembly = Assembly.GetEntryAssembly();
124 | if (rootAssembly == null)
125 | {
126 | rootAssembly = Assembly.GetCallingAssembly();
127 | }
128 | var returnAssemblies = new HashSet(new AssemblyEquality());
129 | var loadedAssemblies = new HashSet();
130 | var assembliesToCheck = new Queue();
131 | assembliesToCheck.Enqueue(rootAssembly);
132 | if (skipSystemAssemblies && IsSystemAssembly(rootAssembly) != false)
133 | {
134 | if (IsValid(rootAssembly))
135 | {
136 | returnAssemblies.Add(rootAssembly);
137 | }
138 | }
139 | while (assembliesToCheck.Any())
140 | {
141 | var assemblyToCheck = assembliesToCheck.Dequeue();
142 | foreach (var reference in assemblyToCheck.GetReferencedAssemblies())
143 | {
144 | if (!loadedAssemblies.Contains(reference.FullName))
145 | {
146 | var assembly = Assembly.Load(reference);
147 | if (skipSystemAssemblies && IsSystemAssembly(assembly))
148 | {
149 | continue;
150 | }
151 | assembliesToCheck.Enqueue(assembly);
152 | loadedAssemblies.Add(reference.FullName);
153 | if (IsValid(assembly))
154 | {
155 | returnAssemblies.Add(assembly);
156 | }
157 | }
158 | }
159 | }
160 | var assembliesInBaseDir = Directory.EnumerateFiles(AppContext.BaseDirectory,
161 | "*.dll", new EnumerationOptions { RecurseSubdirectories = true });
162 | foreach (var asmPath in assembliesInBaseDir)
163 | {
164 | if (!IsManagedAssembly(asmPath))
165 | {
166 | continue;
167 | }
168 | AssemblyName asmName = AssemblyName.GetAssemblyName(asmPath);
169 | //如果程序集已经加载过了就不再加载
170 | if (returnAssemblies.Any(x => AssemblyName.ReferenceMatchesDefinition(x.GetName(), asmName)))
171 | {
172 | continue;
173 | }
174 | if (skipSystemAssemblies && IsSystemAssembly(asmPath))
175 | {
176 | continue;
177 | }
178 | Assembly? asm = TryLoadAssembly(asmPath);
179 | if (asm == null)
180 | {
181 | continue;
182 | }
183 | //Assembly asm = Assembly.Load(asmName);
184 | if (!IsValid(asm))
185 | {
186 | continue;
187 | }
188 | if (skipSystemAssemblies && IsSystemAssembly(asm))
189 | {
190 | continue;
191 | }
192 | returnAssemblies.Add(asm);
193 | }
194 | return returnAssemblies.ToArray();
195 | }
196 |
197 | private static bool IsValid(Assembly asm)
198 | {
199 | try
200 | {
201 | asm.GetTypes();
202 | asm.DefinedTypes.ToList();
203 | return true;
204 | }
205 | catch (ReflectionTypeLoadException)
206 | {
207 | return false;
208 | }
209 | }
210 |
211 | private class AssemblyEquality : EqualityComparer
212 | {
213 | public override bool Equals(Assembly? x, Assembly? y)
214 | {
215 | if (x == null && y == null) return true;
216 | if (x == null || y == null) return false;
217 | return AssemblyName.ReferenceMatchesDefinition(x.GetName(), y.GetName());
218 | }
219 |
220 | public override int GetHashCode([DisallowNull] Assembly obj)
221 | {
222 | return obj.GetName().FullName.GetHashCode();
223 | }
224 | }
225 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/LangKeys.cs:
--------------------------------------------------------------------------------
1 | using Antelcat.I18N.Attributes;
2 |
3 | namespace VisionProcess.Core
4 | {
5 | [ResourceKeysOf(typeof(Strings.Strings))]
6 | public static partial class LangKeys
7 | {
8 | }
9 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Mvvm/NodifyObservableCollection.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 | using System.Collections.Specialized;
3 | using System.ComponentModel;
4 |
5 | namespace VisionProcess.Core.Mvvm
6 | {
7 | public interface INodifyObservableCollection
8 | {
9 | ///
10 | /// Called when a new item is added
11 | ///
12 | /// The callback to execute when an item is added
13 | /// Returns self
14 | INodifyObservableCollection WhenAdded(Action added);
15 |
16 | ///
17 | /// Called when an existing item is removed
18 | /// Note: It is not called when items are cleared if is used
19 | ///
20 | /// The callback to execute when an item is removed
21 | /// Returns self
22 | INodifyObservableCollection WhenRemoved(Action removed);
23 |
24 | ///
25 | /// Called when the collection is cleared
26 | /// NOTE: It does not call on each item
27 | ///
28 | /// The callback to execute when the collection is cleared
29 | /// Returns self
30 | INodifyObservableCollection WhenCleared(Action> cleared);
31 | }
32 |
33 | public class NodifyObservableCollection : Collection, INodifyObservableCollection, INotifyPropertyChanged, INotifyCollectionChanged
34 | {
35 | protected static readonly PropertyChangedEventArgs IndexerPropertyChanged = new("Item[]");
36 | protected static readonly PropertyChangedEventArgs CountPropertyChanged = new("Count");
37 | protected static readonly NotifyCollectionChangedEventArgs ResetCollectionChanged = new(NotifyCollectionChangedAction.Reset);
38 |
39 | private readonly List> _added = new();
40 | private readonly List> _removed = new();
41 | private readonly List>> _cleared = new();
42 |
43 | public event NotifyCollectionChangedEventHandler? CollectionChanged;
44 |
45 | public event PropertyChangedEventHandler? PropertyChanged;
46 |
47 | public NodifyObservableCollection()
48 | {
49 | }
50 |
51 | public NodifyObservableCollection(IEnumerable collection)
52 | : base(new List(collection))
53 | {
54 | }
55 |
56 | #region Collection Events
57 |
58 | public INodifyObservableCollection WhenAdded(Action added)
59 | {
60 | if (added != null)
61 | {
62 | _added.Add(added);
63 | }
64 | return this;
65 | }
66 |
67 | public INodifyObservableCollection WhenRemoved(Action removed)
68 | {
69 | if (removed != null)
70 | {
71 | _removed.Add(removed);
72 | }
73 | return this;
74 | }
75 |
76 | public INodifyObservableCollection WhenCleared(Action> cleared)
77 | {
78 | if (cleared != null)
79 | {
80 | _cleared.Add(cleared);
81 | }
82 | return this;
83 | }
84 |
85 | protected virtual void NotifyOnItemAdded(T item)
86 | {
87 | for (int i = 0; i < _added.Count; i++)
88 | {
89 | _added[i](item);
90 | }
91 | }
92 |
93 | protected virtual void NotifyOnItemRemoved(T item)
94 | {
95 | for (int i = 0; i < _removed.Count; i++)
96 | {
97 | _removed[i](item);
98 | }
99 | }
100 |
101 | protected virtual void NotifyOnItemsCleared(IList items)
102 | {
103 | for (int i = 0; i < _cleared.Count; i++)
104 | {
105 | _cleared[i](items);
106 | }
107 | }
108 |
109 | #endregion Collection Events
110 |
111 | #region Collection Handlers
112 |
113 | protected override void ClearItems()
114 | {
115 | var items = new List(this);
116 | base.ClearItems();
117 |
118 | if (_cleared.Count > 0)
119 | {
120 | NotifyOnItemsCleared(items);
121 | }
122 | else
123 | {
124 | for (int i = 0; i < items.Count; i++)
125 | {
126 | NotifyOnItemRemoved(items[i]);
127 | }
128 | }
129 |
130 | OnPropertyChanged(CountPropertyChanged);
131 | OnPropertyChanged(IndexerPropertyChanged);
132 | OnCollectionChanged(ResetCollectionChanged);
133 | }
134 |
135 | protected override void InsertItem(int index, T item)
136 | {
137 | base.InsertItem(index, item);
138 |
139 | OnPropertyChanged(CountPropertyChanged);
140 | OnPropertyChanged(IndexerPropertyChanged);
141 | OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
142 | NotifyOnItemAdded(item);
143 | }
144 |
145 | protected override void RemoveItem(int index)
146 | {
147 | var item = base[index];
148 | base.RemoveItem(index);
149 |
150 | OnPropertyChanged(CountPropertyChanged);
151 | OnPropertyChanged(IndexerPropertyChanged);
152 | OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index);
153 | NotifyOnItemRemoved(item);
154 | }
155 |
156 | protected override void SetItem(int index, T item)
157 | {
158 | T prev = base[index];
159 | base.SetItem(index, item);
160 | OnPropertyChanged(IndexerPropertyChanged);
161 | OnCollectionChanged(NotifyCollectionChangedAction.Replace, prev, item, index);
162 | NotifyOnItemRemoved(prev);
163 | NotifyOnItemAdded(item);
164 | }
165 |
166 | public void Move(int oldIndex, int newIndex)
167 | {
168 | T prev = base[oldIndex];
169 | base.RemoveItem(oldIndex);
170 | base.InsertItem(newIndex, prev);
171 | OnPropertyChanged(IndexerPropertyChanged);
172 | OnCollectionChanged(NotifyCollectionChangedAction.Move, prev, newIndex, oldIndex);
173 | }
174 |
175 | protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
176 | => CollectionChanged?.Invoke(this, e);
177 |
178 | protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
179 | => PropertyChanged?.Invoke(this, args);
180 |
181 | private void OnCollectionChanged(NotifyCollectionChangedAction action, object? item, int index)
182 | => OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
183 |
184 | private void OnCollectionChanged(NotifyCollectionChangedAction action, object? item, int index, int oldIndex)
185 | => OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index, oldIndex));
186 |
187 | private void OnCollectionChanged(NotifyCollectionChangedAction action, object? oldItem, object? newItem, int index)
188 | => OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
189 |
190 | #endregion Collection Handlers
191 | }
192 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Shapes/IVpShape.cs:
--------------------------------------------------------------------------------
1 | namespace VisionProcess.Core.Shapes
2 | {
3 | ///
4 | /// To be added
5 | ///
6 | public interface IVpShape
7 | {
8 | }
9 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/Strings/Strings.ar-DZ.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | لم يتم العثور على المجلد "{0}"
122 |
123 |
124 | تم رفض الوصول إلى المجلد "{0}"
125 |
126 |
127 | إلغاء
128 |
129 |
130 | إغلاق
131 |
132 |
133 | إنشاء
134 |
135 |
136 | منشأ
137 |
138 |
139 | سطح المكتب
140 |
141 |
142 | التفاصيل
143 |
144 |
145 | المستندات
146 |
147 |
148 | الأقراص
149 |
150 |
151 | مجلد فارغ
152 |
153 |
154 | الملفات
155 |
156 |
157 | حجم الملف
158 |
159 |
160 | المجلدات
161 |
162 |
163 | آخر ولوج
164 |
165 |
166 | آخر تعديل
167 |
168 |
169 | قرص محلي
170 |
171 |
172 | المسارات الطويلة غير مدعومة
173 |
174 |
175 | تكبير
176 |
177 |
178 | تصغير
179 |
180 |
181 | الموسيقى
182 |
183 |
184 | إسم دليل جديد
185 |
186 |
187 | لم يتم تحديد مجلدات
188 |
189 |
190 | لم يتم تحديد ملفات
191 |
192 |
193 | موافق
194 |
195 |
196 | فتح
197 |
198 |
199 | فتح ملف
200 |
201 |
202 | الصور
203 |
204 |
205 | حذف
206 |
207 |
208 | إستعادة
209 |
210 |
211 | حفظ
212 |
213 |
214 | حفظ الملف
215 |
216 |
217 | البحث
218 |
219 |
220 | تحديد
221 |
222 |
223 | إختيار مجلد
224 |
225 |
226 | إختيار
227 |
228 |
229 | اسم الدليل غير صالح
230 |
231 |
232 | يجب ألا يكون اسم الدليل فارغًا
233 |
234 |
235 | الدليل '{0}' موجود بالفعل
236 |
237 |
238 | المستخدم
239 |
240 |
241 | الفيديوهات
242 |
243 |
--------------------------------------------------------------------------------
/VisionProcess.Core/Strings/Strings.ru-RU.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Папка '{0}' не найдена
122 |
123 |
124 | Доступ к папке '{0}' запрещен
125 |
126 |
127 | Отмена
128 |
129 |
130 | Закрыть
131 |
132 |
133 | Создать
134 |
135 |
136 | Создан
137 |
138 |
139 | Рабочий стол
140 |
141 |
142 | Информация
143 |
144 |
145 | Документы
146 |
147 |
148 | Устройства и диски
149 |
150 |
151 | Пустая папка
152 |
153 |
154 | Файлы
155 |
156 |
157 | Размер файла
158 |
159 |
160 | Папки
161 |
162 |
163 | Открыт
164 |
165 |
166 | Изменен
167 |
168 |
169 | Локальный диск
170 |
171 |
172 | Длинные пути не поддерживаются
173 |
174 |
175 | Развернуть
176 |
177 |
178 | Свернуть
179 |
180 |
181 | Музыка
182 |
183 |
184 | Название новой директории
185 |
186 |
187 | Не выбраны директории
188 |
189 |
190 | Не выбраны файлы
191 |
192 |
193 | Открыть
194 |
195 |
196 | Открыть файл
197 |
198 |
199 | Изображения
200 |
201 |
202 | Удалить
203 |
204 |
205 | Восстановить
206 |
207 |
208 | Сохранить
209 |
210 |
211 | Сохранить файл
212 |
213 |
214 | Поиск
215 |
216 |
217 | Выбрать
218 |
219 |
220 | Выбрать папку
221 |
222 |
223 | Выбрано
224 |
225 |
226 | Некорректное наименование директории
227 |
228 |
229 | Наименование директории не должно быть пустым
230 |
231 |
232 | Директория '{0}' уже существует
233 |
234 |
235 | Этот компьютер
236 |
237 |
238 | Видео
239 |
240 |
--------------------------------------------------------------------------------
/VisionProcess.Core/Strings/Strings.uz-Latn-UZ.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | '{0}' papka topilmadi
122 |
123 |
124 | '{0}' papkaga kirish rad etildi
125 |
126 |
127 | Bekor qilish
128 |
129 |
130 | Yopish
131 |
132 |
133 | Yaratildi
134 |
135 |
136 | Ish stoli
137 |
138 |
139 | Hujjatlar
140 |
141 |
142 | Drayvlar
143 |
144 |
145 | Bo'sh papka
146 |
147 |
148 | Fayllar
149 |
150 |
151 | Fayl hajmi
152 |
153 |
154 | Papkalar
155 |
156 |
157 | So'nggi kirish
158 |
159 |
160 | Oxirgi o'zgartirishlar kiritilgan
161 |
162 |
163 | Mahalliy draiver
164 |
165 |
166 | Fayl joylashgan joyga yo'l juda uzun bo'lsa, qo'llab-quvvatlanmaydi
167 |
168 |
169 | Musiqa
170 |
171 |
172 | Ochish
173 |
174 |
175 | Faylni ochish
176 |
177 |
178 | Rasmlar
179 |
180 |
181 | Saqlash
182 |
183 |
184 | Faylni saqlash
185 |
186 |
187 | Qidirish
188 |
189 |
190 | Tanlash
191 |
192 |
193 | Papkani tanlash
194 |
195 |
196 | Foydalanuvchi
197 |
198 |
199 | Videolar
200 |
201 |
202 | 値
203 |
204 |
205 | 接続を解除
206 |
207 |
208 | フィルタ タイプ
209 |
210 |
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/GraphicsBase.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 |
3 | namespace VisionProcess.Core.ToolBase
4 | {
5 | ///
6 | /// To be added
7 | ///
8 | public abstract class GraphicsBase : ObservableObject, IGraphics
9 | {
10 | }
11 |
12 | public class GraphicsEmpty : GraphicsBase
13 | {
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/IGraphics.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace VisionProcess.Core.ToolBase
4 | {
5 | ///
6 | /// To be added
7 | ///
8 | public interface IGraphics: INotifyPropertyChanged
9 | {
10 | }
11 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/IInputs.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace VisionProcess.Core.ToolBase
4 | {
5 | ///
6 | /// To be added
7 | ///
8 | public interface IInputs:INotifyPropertyChanged
9 | {
10 | }
11 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/IOperator.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.Input;
2 | using System.Collections.ObjectModel;
3 |
4 | namespace VisionProcess.Core.ToolBase
5 | {
6 | public interface IOperator
7 | {
8 | event EventHandler? Executed;
9 |
10 | event EventHandler? Executing;
11 |
12 | IAsyncRelayCommand? ExecuteCommand { get; }
13 | IGraphics Graphics { get; }
14 | IInputs Inputs { get; }
15 | bool IsRealTime { get; set; }
16 | string? Name { get; set; }
17 | IOutputs Outputs { get; }
18 | ObservableCollection Records { get; }
19 | RunStatus RunStatus { get; }
20 |
21 | Task ExecuteAsync();
22 | }
23 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/IOutputs.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace VisionProcess.Core.ToolBase
4 | {
5 | ///
6 | /// To be added
7 | ///
8 | public interface IOutputs:INotifyPropertyChanged
9 | {
10 | }
11 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/InputsBase.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 |
3 | namespace VisionProcess.Core.ToolBase
4 | {
5 | ///
6 | /// To be added
7 | ///
8 | public abstract class InputsBase : ObservableObject, IInputs
9 | {
10 | }
11 |
12 | public class InputsEmpty : InputsBase
13 | {
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/OperatorBase.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using OpenCvSharp;
4 | using Newtonsoft.Json;
5 | using System.Collections.ObjectModel;
6 | using System.Diagnostics;
7 | using VisionProcess.Core.Attributes;
8 |
9 | namespace VisionProcess.Core.ToolBase
10 | {
11 | public abstract partial class OperatorBase
12 | : ObservableObject, IOperator
13 | where TInputs : IInputs, new() where TOutputs : IOutputs, new() where TGraphics : IGraphics, new()
14 | {
15 | [ObservableProperty]
16 | private string? name;
17 | private readonly object locker = new object();
18 | private readonly Stopwatch stopwatch = new();
19 | private bool isRealTime;
20 |
21 | //子类可依赖注入
22 | protected OperatorBase()
23 | {
24 | }
25 |
26 | protected OperatorBase(TInputs inputs, TOutputs outputs, TGraphics graphics, RunStatus runStatus)
27 | {
28 | Inputs = inputs;
29 | Outputs = outputs;
30 | Graphics = graphics;
31 | RunStatus = runStatus;
32 | }
33 | public event EventHandler? Executed;
34 |
35 | public event EventHandler? Executing;
36 | [ThresholdIgnore]
37 | public TGraphics Graphics { get; } = new TGraphics();
38 | IGraphics IOperator.Graphics => Graphics;
39 | public TInputs Inputs { get; } = new TInputs();
40 | IInputs IOperator.Inputs => Inputs;
41 |
42 | public bool IsRealTime
43 | {
44 | get { return isRealTime; }
45 | set
46 | {
47 | if (value)
48 | {
49 | Inputs.PropertyChanged -= ExecuteWhenInputs_PropertyChanged;
50 | Inputs.PropertyChanged += ExecuteWhenInputs_PropertyChanged;
51 | }
52 | else
53 | {
54 | Inputs.PropertyChanged -= ExecuteWhenInputs_PropertyChanged;
55 | }
56 | SetProperty(ref isRealTime, value);
57 | }
58 | }
59 |
60 | IOutputs IOperator.Outputs => Outputs;
61 | public TOutputs Outputs { get; } = new TOutputs();
62 | //[ThresholdIgnore]
63 | public ObservableCollection Records { get; } = new ObservableCollection();
64 |
65 | public RunStatus RunStatus { get; } = new RunStatus();
66 |
67 | private void Execute()
68 | {
69 | OnExecuting();
70 |
71 | stopwatch.Reset();
72 | stopwatch.Start();
73 |
74 | RunStatus.Exception = null;
75 | try
76 | {
77 | RunStatus.LastTime = DateTime.Now;
78 | RunStatus.Result = InternalExecute(out string message);
79 | RunStatus.Message = message;
80 | }
81 | catch (OpenCVException ex)
82 | {
83 | RunStatus.Result = false;
84 | RunStatus.Exception = ex;
85 | RunStatus.Message = ex.Message;
86 | }
87 | catch (ArgumentNullException ex)
88 | {
89 | RunStatus.Result = false;
90 | RunStatus.Exception = ex;
91 | RunStatus.Message = ex.Message;
92 | }
93 | catch (Exception ex)
94 | {
95 | RunStatus.Result = false;
96 | RunStatus.Exception = ex;
97 | RunStatus.Message = ex.Message;
98 | }
99 | finally
100 | {
101 | stopwatch.Stop();
102 | RunStatus.ProcessingTime = stopwatch.ElapsedMilliseconds;
103 | OnExecuted();
104 | }
105 | }
106 |
107 | protected abstract bool InternalExecute(out string message);
108 |
109 | protected virtual void OnExecuted()
110 | {
111 | Executed?.Invoke(this, EventArgs.Empty);
112 | }
113 |
114 | protected virtual void OnExecuting()
115 | {
116 | Executing?.Invoke(this, EventArgs.Empty);
117 | }
118 |
119 | [property: JsonIgnore]
120 | [RelayCommand]
121 | public async Task ExecuteAsync()
122 | {
123 | await Task.Run(() =>
124 | {
125 | lock (locker)
126 | {
127 | Execute();
128 | }
129 | });
130 | }
131 |
132 | private void ExecuteWhenInputs_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
133 | {
134 | Execute();
135 | }
136 | }
137 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/OutputsBase.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 |
3 | namespace VisionProcess.Core.ToolBase
4 | {
5 | ///
6 | /// To be added
7 | ///
8 | public abstract class OutputsBase : ObservableObject, IOutputs
9 | {
10 | }
11 |
12 | public class OutputsEmpty : OutputsBase
13 | {
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/Record.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using Newtonsoft.Json;
3 | using OpenCvSharp;
4 | using OpenCvSharp.WpfExtensions;
5 | using System.Windows.Media.Imaging;
6 | using VisionProcess.Core.Attributes;
7 |
8 | namespace VisionProcess.Core.ToolBase
9 | {
10 | public class Record : ObservableObject
11 | {
12 | private string? title;
13 |
14 | public string? Title
15 | {
16 | get { return title; }
17 | set { SetProperty(ref title, value); }
18 | }
19 |
20 | private BitmapSource? displayImage;
21 | //[ThresholdIgnore]
22 | [JsonIgnore]
23 | public BitmapSource? DisplayImage
24 | {
25 | get
26 | {
27 | return displayImage;
28 | }
29 | set
30 | {
31 | if (value != displayImage)
32 | {
33 | displayImage = value;
34 | displayImage?.Freeze();
35 | //System.Windows.Application.Current.Dispatcher.Invoke(() =>
36 | //{
37 | OnPropertyChanged();
38 | //});
39 | }
40 | }
41 | }
42 | [ThresholdIgnore]
43 | [JsonProperty(nameof(DisplayImage))]
44 | public byte[]? DisplayImageBytes
45 | {
46 | get
47 | {
48 | if (displayImage is null)
49 | return null;
50 | return BitmapSourceConverter.ToMat(displayImage).ToBytes();
51 | }
52 | set
53 | {
54 | if (value is not null)
55 | {
56 | using var mat = Cv2.ImDecode(value, ImreadModes.Unchanged);
57 | DisplayImage = mat.ToBitmapSource();
58 | }
59 | }
60 | }
61 |
62 | //private string _shapes;
63 | //public string Shapes
64 | //{
65 | // get { return _shapes; }
66 | // set { SetProperty(ref _shapes, value); }
67 | //}
68 | }
69 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/ToolBase/RunStatus.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using Newtonsoft.Json;
3 | using VisionProcess.Core.Attributes;
4 |
5 | namespace VisionProcess.Core.ToolBase
6 | {
7 | public class RunStatus : ObservableObject
8 | {
9 | private Exception? exception;
10 |
11 | private DateTime lastTime = DateTime.Now;
12 |
13 | private string message = "";
14 |
15 | private double processingTime = 0;
16 |
17 | private bool result = false;
18 |
19 | public RunStatus()
20 | {
21 | }
22 |
23 | public RunStatus(string message)
24 | {
25 | this.message = message;
26 | }
27 |
28 | public RunStatus(Exception exception)
29 | {
30 | this.exception = exception;
31 | }
32 |
33 | [JsonConstructor]
34 | public RunStatus(DateTime lastTime, string message, double processingTime, bool result)
35 | {
36 | this.lastTime = lastTime;
37 | this.message = message;
38 | this.processingTime = processingTime;
39 | this.result = result;
40 | }
41 | [JsonIgnore]
42 | [ThresholdIgnore]
43 | public Exception? Exception
44 | {
45 | get { return exception; }
46 | internal set { SetProperty(ref exception, value); }
47 | }
48 |
49 | public DateTime LastTime
50 | {
51 | get { return lastTime; }
52 | internal set { SetProperty(ref lastTime, value); }
53 | }
54 |
55 | public string Message
56 | {
57 | get { return message; }
58 | internal set { SetProperty(ref message, value); }
59 | }
60 |
61 | public double ProcessingTime
62 | {
63 | get { return processingTime; }
64 | internal set { SetProperty(ref processingTime, value); }
65 | }
66 |
67 | public bool Result
68 | {
69 | get { return result; }
70 | internal set { SetProperty(ref result, value); }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/VisionProcess.Core/VisionProcess.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0-windows7.0
5 | true
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | True
33 | True
34 | Strings.resx
35 |
36 |
37 |
38 |
39 |
40 | PublicResXFileCodeGenerator
41 | Strings.Designer.cs
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/VisionProcess.Tools/Models/AcquireImageOutputs.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp;
3 | using VisionProcess.Core.Attributes;
4 | using VisionProcess.Core.ToolBase;
5 |
6 | namespace VisionProcess.Tools.Models
7 | {
8 | public class AcquireImageOutputs : OutputsBase
9 | {
10 | private Mat? image;
11 |
12 | [JsonIgnore]
13 | public Mat? Image
14 | {
15 | get
16 | {
17 | return image;
18 | }
19 | internal set
20 | {
21 | if (image != value)
22 | {
23 | image?.Dispose();
24 | image = value;
25 | }
26 | }
27 | }
28 | [ThresholdIgnore]
29 | [JsonProperty(nameof(Image))]
30 | public byte[]? ImageBytes
31 | {
32 | get { return Image?.ToBytes(); }
33 | set
34 | {
35 | if (value is not null)
36 | {
37 | Image = Cv2.ImDecode(value, ImreadModes.Unchanged);
38 | }
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Models/ColorConvertInputs.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp;
3 | using VisionProcess.Core.Attributes;
4 | using VisionProcess.Core.ToolBase;
5 |
6 | namespace VisionProcess.Tools.Models
7 | {
8 | public class ColorConvertInputs : InputsBase
9 | {
10 | private ColorConversionCodes colorConversionCodes = ColorConversionCodes.BGR2GRAY;
11 | private Mat? image;
12 |
13 | public ColorConversionCodes ColorConversionCodes
14 | {
15 | get { return colorConversionCodes; }
16 | set { SetProperty(ref colorConversionCodes, value); }
17 | }
18 |
19 | [JsonIgnore]
20 | public Mat? Image
21 | {
22 | get
23 | {
24 | return image;
25 | }
26 | set
27 | {
28 | if (image != value)
29 | {
30 | image?.Dispose();
31 | image = value;
32 | OnPropertyChanged();
33 | }
34 | }
35 | }
36 | [ThresholdIgnore]
37 | [JsonProperty(nameof(Image))]
38 | public byte[]? ImageBytes
39 | {
40 | get { return Image?.ToBytes(); }
41 | set
42 | {
43 | if (value is not null)
44 | {
45 | Image = Cv2.ImDecode(value, ImreadModes.Unchanged);
46 | }
47 | }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Models/ColorConvertOutputs.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp;
3 | using VisionProcess.Core.Attributes;
4 | using VisionProcess.Core.ToolBase;
5 |
6 | namespace VisionProcess.Tools.Models
7 | {
8 | public class ColorConvertOutputs : OutputsBase
9 | {
10 | private Mat? image;
11 |
12 | [JsonIgnore]
13 | public Mat? Image
14 | {
15 | get
16 | {
17 | return image;
18 | }
19 | internal set
20 | {
21 | if (image != value)
22 | {
23 | image?.Dispose();
24 | image = value;
25 | }
26 | }
27 | }
28 | [ThresholdIgnore]
29 | [JsonProperty(nameof(Image))]
30 | public byte[]? ImageBytes
31 | {
32 | get { return Image?.ToBytes(); }
33 | set
34 | {
35 | if (value is not null)
36 | {
37 | Image = Cv2.ImDecode(value, ImreadModes.Unchanged);
38 | }
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Models/ImageFilterInputs.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp;
3 | using System.ComponentModel;
4 | using VisionProcess.Core.Attributes;
5 | using VisionProcess.Core.Converters;
6 | using VisionProcess.Core.Strings;
7 | using VisionProcess.Core.ToolBase;
8 |
9 | namespace VisionProcess.Tools.Models
10 | {
11 | [TypeConverter(typeof(EnumDescriptionTypeConverter))]
12 | public enum FilterTypes
13 | {
14 | [LocalizedDescription("NormalizedBox", typeof(Strings))]
15 | NormalizedBox,
16 |
17 | [LocalizedDescription("Median", typeof(Strings))]
18 | Median,
19 |
20 | [LocalizedDescription("Gaussian", typeof(Strings))]
21 | Gaussian,
22 |
23 | [LocalizedDescription("Bilateral", typeof(Strings))]
24 | Bilateral,
25 | }
26 |
27 | public class ImageFilterInputs : InputsBase
28 | {
29 | private BorderTypes borderType = BorderTypes.Default;
30 | private FilterTypes filterType = FilterTypes.Median;
31 | private Mat? image;
32 |
33 | private int kernelHeight = 3;
34 |
35 | private int kernelWidth = 3;
36 |
37 | ///
38 | /// pixel extrapolation method
39 | ///
40 | public BorderTypes BorderType
41 | {
42 | get { return borderType; }
43 | set { SetProperty(ref borderType, value); }
44 | }
45 |
46 | public FilterTypes FilterType
47 | {
48 | get { return filterType; }
49 | set { SetProperty(ref filterType, value); }
50 | }
51 |
52 | [JsonIgnore]
53 | public Mat? Image
54 | {
55 | get
56 | {
57 | return image;
58 | }
59 | set
60 | {
61 | if (image != value)
62 | {
63 | image?.Dispose();
64 | image = value;
65 | OnPropertyChanged();
66 | }
67 | }
68 | }
69 | [ThresholdIgnore]
70 | [JsonProperty(nameof(Image))]
71 | public byte[]? ImageBytes
72 | {
73 | get { return Image?.ToBytes(); }
74 | set
75 | {
76 | if (value is not null)
77 | {
78 | Image = Cv2.ImDecode(value, ImreadModes.Unchanged);
79 | }
80 | }
81 | }
82 |
83 | public int KernelHeight
84 | {
85 | get { return kernelHeight; }
86 | set { SetProperty(ref kernelHeight, value); }
87 | }
88 |
89 | public int KernelWidth
90 | {
91 | get { return kernelWidth; }
92 | set { SetProperty(ref kernelWidth, value); }
93 | }
94 |
95 | #region Median
96 |
97 | private int _kernelSize = 3;
98 |
99 | public int KernelSize
100 | {
101 | get { return _kernelSize; }
102 | set { SetProperty(ref _kernelSize, value); }
103 | }
104 |
105 | #endregion Median
106 |
107 | #region Gaussian
108 |
109 | private double _sigmaX = 3;
110 | private double _sigmaY = 0;
111 |
112 | ///
113 | /// Gaussian kernel standard deviation in X direction.
114 | ///
115 | public double SigmaX
116 | {
117 | get { return _sigmaX; }
118 | set { SetProperty(ref _sigmaX, value); }
119 | }
120 |
121 | ///
122 | /// Gaussian kernel standard deviation in Y direction; if sigmaY is zero, it is set to be equal to sigmaX,
123 | /// if both sigmas are zeros, they are computed from ksize.width and ksize.height,
124 | /// respectively (see getGaussianKernel() for details); to fully control the result
125 | /// regardless of possible future modifications of all this semantics, it is recommended to specify all of ksize, sigmaX, and sigmaY.
126 | ///
127 | public double SigmaY
128 | {
129 | get { return _sigmaY; }
130 | set { SetProperty(ref _sigmaY, value); }
131 | }
132 |
133 | #endregion Gaussian
134 |
135 | #region BilateralFilter
136 |
137 | private int _diameter = 1;
138 | private double _sigmaColor = 1;
139 |
140 | private double _sigmaSpace = 1;
141 |
142 | ///
143 | /// The diameter of each pixel neighborhood, that is used during filtering.
144 | /// If it is non-positive, it's computed from sigmaSpace
145 | ///
146 | public int Diameter
147 | {
148 | get { return _diameter; }
149 | set { SetProperty(ref _diameter, value); }
150 | }
151 |
152 | ///
153 | /// Filter sigma in the color space.
154 | /// Larger value of the parameter means that farther colors within the pixel neighborhood
155 | /// will be mixed together, resulting in larger areas of semi-equal color
156 | ///
157 | public double SigmaColor
158 | {
159 | get { return _sigmaColor; }
160 | set { SetProperty(ref _sigmaColor, value); }
161 | }
162 |
163 | ///
164 | /// Filter sigma in the coordinate space.
165 | /// Larger value of the parameter means that farther pixels will influence each other
166 | /// (as long as their colors are close enough; see sigmaColor). Then d>0 , it specifies
167 | /// the neighborhood size regardless of sigmaSpace, otherwise d is proportional to sigmaSpace
168 | ///
169 | public double SigmaSpace
170 | {
171 | get { return _sigmaSpace; }
172 | set { SetProperty(ref _sigmaSpace, value); }
173 | }
174 |
175 | #endregion BilateralFilter
176 | }
177 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Models/ImageFilterOutputs.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp;
3 | using VisionProcess.Core.Attributes;
4 | using VisionProcess.Core.ToolBase;
5 |
6 | namespace VisionProcess.Tools.Models
7 | {
8 | public class ImageFilterOutputs : OutputsBase
9 | {
10 | private Mat? image;
11 |
12 | [JsonIgnore]
13 | public Mat? Image
14 | {
15 | get
16 | {
17 | return image;
18 | }
19 | internal set
20 | {
21 | if (image != value)
22 | {
23 | image?.Dispose();
24 | image = value;
25 | }
26 | }
27 | }
28 | [ThresholdIgnore]
29 | [JsonProperty(nameof(Image))]
30 | public byte[]? ImageBytes
31 | {
32 | get { return Image?.ToBytes(); }
33 | set
34 | {
35 | if (value is not null)
36 | {
37 | Image = Cv2.ImDecode(value, ImreadModes.Unchanged);
38 | }
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Models/ImageThresholdInputs.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp;
3 | using VisionProcess.Core.Attributes;
4 | using VisionProcess.Core.ToolBase;
5 |
6 | namespace VisionProcess.Tools.Models
7 | {
8 | public class ImageThresholdInputs : InputsBase
9 | {
10 | private Mat? image;
11 | private double maximumValue = 255;
12 | private ThresholdTypes thresholdType = ThresholdTypes.Binary;
13 | private double thresholdValue = 50;
14 |
15 | [JsonIgnore]
16 | public Mat? Image
17 | {
18 | get
19 | {
20 | return image;
21 | }
22 | set
23 | {
24 | if (image != value)
25 | {
26 | image?.Dispose();
27 | image = value;
28 | OnPropertyChanged();
29 | }
30 | }
31 | }
32 | [ThresholdIgnore]
33 | [JsonProperty(nameof(Image))]
34 | public byte[]? ImageBytes
35 | {
36 | get { return Image?.ToBytes(); }
37 | set
38 | {
39 | if (value is not null)
40 | {
41 | Image = Cv2.ImDecode(value, ImreadModes.Unchanged);
42 | }
43 | }
44 | }
45 |
46 | ///
47 | /// maximum value to use with the THRESH_BINARY and THRESH_BINARY_INV thresholding types
48 | ///
49 | public double MaximumValue
50 | {
51 | get { return maximumValue; }
52 | set { SetProperty(ref maximumValue, value); }
53 | }
54 |
55 | ///
56 | /// thresholding type (see the details below).
57 | ///
58 | public ThresholdTypes ThresholdType
59 | {
60 | get { return thresholdType; }
61 | set { SetProperty(ref thresholdType, value); }
62 | }
63 |
64 | ///
65 | /// threshold value
66 | ///
67 | public double ThresholdValue
68 | {
69 | get { return thresholdValue; }
70 | set { SetProperty(ref thresholdValue, value); }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Models/ImageThresholdOutputs.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp;
3 | using VisionProcess.Core.Attributes;
4 | using VisionProcess.Core.ToolBase;
5 |
6 | namespace VisionProcess.Tools.Models
7 | {
8 | public class ImageThresholdOutputs : OutputsBase
9 | {
10 | private Mat? image;
11 |
12 | [JsonIgnore]
13 | public Mat? Image
14 | {
15 | get
16 | {
17 | return image;
18 | }
19 | internal set
20 | {
21 | if (image != value)
22 | {
23 | image?.Dispose();
24 | image = value;
25 | }
26 | }
27 | }
28 | [ThresholdIgnore]
29 | [JsonProperty(nameof(Image))]
30 | public byte[]? ImageBytes
31 | {
32 | get { return Image?.ToBytes(); }
33 | set
34 | {
35 | if (value is not null)
36 | {
37 | Image = Cv2.ImDecode(value, ImreadModes.Unchanged);
38 | }
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/ToolsDictionary.xaml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/VisionProcess.Tools/ViewModels/AcquireImageViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.Input;
2 | using Microsoft.Win32;
3 | using Newtonsoft.Json;
4 | using OpenCvSharp;
5 | using OpenCvSharp.WpfExtensions;
6 | using System.Collections.Generic;
7 | using System.Collections.ObjectModel;
8 | using System.Linq;
9 | using System.Threading.Tasks;
10 | using VisionProcess.Core.Attributes;
11 | using VisionProcess.Core.Strings;
12 | using VisionProcess.Core.ToolBase;
13 | using VisionProcess.Tools.Models;
14 |
15 | namespace VisionProcess.Tools.ViewModels
16 | {
17 | [DefaultToolConnector(false, "Image", "Outputs.Image")]
18 | public partial class AcquireImageViewModel : OperatorBase
19 | {
20 | public AcquireImageViewModel() : base()
21 | {
22 | Init();
23 | }
24 |
25 | [JsonConstructor]
26 | public AcquireImageViewModel(InputsEmpty inputs, AcquireImageOutputs outputs, GraphicsEmpty graphics, RunStatus runStatus)
27 | : base(inputs, outputs, graphics, runStatus)
28 | {
29 | }
30 |
31 | private int currentIndex = 0;
32 | private List? imagePaths;
33 |
34 | internal int CurrentIndex
35 | {
36 | get { return currentIndex; }
37 | set { currentIndex = value; }
38 | }
39 | internal List? ImagePaths
40 | {
41 | get { return imagePaths; }
42 | set { imagePaths = value; }
43 | }
44 |
45 | protected override bool InternalExecute(out string message)
46 | {
47 | if (imagePaths == null || imagePaths.Count < 1)
48 | {
49 | message = Strings.PleaseSelectFiles;
50 | //message = "Please select image files";
51 | return false;
52 | }
53 |
54 | if (currentIndex > imagePaths.Count - 1)
55 | {
56 | currentIndex = 0;
57 | }
58 | Outputs.Image = new Mat(imagePaths[currentIndex]);
59 | Records[^1].DisplayImage = Outputs.Image.ToBitmapSource();
60 |
61 | currentIndex++;
62 | ////延时
63 | //Thread.Sleep(1000);
64 | message = Strings.Success;
65 | return true;
66 | }
67 |
68 | [property: JsonIgnore]
69 | [RelayCommand]
70 | private async Task AcquireLocalImagesAsync()
71 | {
72 | var dialog = new OpenFileDialog();
73 | //dialog.FileName = "Document"; // Default file name
74 | dialog.Multiselect = true;
75 | //dialog.DefaultExt = ".txt"; // Default file extension
76 | dialog.Filter = $"{Strings.ImageFiles} (*.jpg*.bmp*.png)|*.jpg;*.bmp;*.png"; // Filter files by extension
77 | dialog.Title = $"{Strings.PleaseSelectFiles}";
78 | // Show open file dialog box
79 | bool? result = dialog.ShowDialog();
80 |
81 | // Process open file dialog box results
82 | if (result == true)
83 | {
84 | // Open document
85 | //string filename = dialog.FileName;
86 | imagePaths = dialog.FileNames.ToList();
87 | currentIndex = 0;
88 | await ExecuteAsync();
89 | }
90 | }
91 |
92 | private void Init()
93 | {
94 | Records.Add(new() { Title = Strings.OutputImage });
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/ViewModels/ColorConvertViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp.WpfExtensions;
3 | using System.Collections.ObjectModel;
4 | using System.Drawing;
5 | using VisionProcess.Core.Attributes;
6 | using VisionProcess.Core.Strings;
7 | using VisionProcess.Core.ToolBase;
8 | using VisionProcess.Tools.Models;
9 |
10 | namespace VisionProcess.Tools.ViewModels
11 | {
12 | [DefaultToolConnector(true, "Image", "Inputs.Image")]
13 | [DefaultToolConnector(false, "Image", "Outputs.Image")]
14 | public class ColorConvertViewModel : OperatorBase
15 | {
16 | public ColorConvertViewModel() : base()
17 | {
18 | Init();
19 | Inputs.PropertyChanged += Inputs_PropertyChanged;
20 | }
21 |
22 | [JsonConstructor]
23 | public ColorConvertViewModel(ColorConvertInputs inputs, ColorConvertOutputs outputs, GraphicsEmpty graphics, RunStatus runStatus)
24 | : base(inputs, outputs, graphics, runStatus)
25 | {
26 | Inputs.PropertyChanged += Inputs_PropertyChanged;
27 | }
28 |
29 | protected override bool InternalExecute(out string message)
30 | {
31 | if (Inputs.Image is null)
32 | {
33 | message = "Input image can not be null";
34 | return false;
35 | }
36 | //Cv2.CvtColor(Inputs.Image, Outputs.Image, ColorConversionCodes.RGB2BGRA);//RGB2BGRA? BRG2BGRA?
37 | Outputs.Image = Inputs.Image.CvtColor(Inputs.ColorConversionCodes);
38 | Records[0].DisplayImage = Outputs.Image.ToBitmapSource();
39 |
40 | //to one channel ?
41 | //R*Weight
42 | //G*Weight
43 | //B*Weight
44 | //...............................................................
45 | message = Strings.Success;
46 |
47 | return true;
48 | }
49 |
50 | private void Init()
51 | {
52 | Records.Add(new() { Title = Strings.OutputImage });
53 | Records.Add(new() { Title = Strings.InputImage });
54 | }
55 |
56 | private void Inputs_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
57 | {
58 | if (e.PropertyName?.Equals(nameof(Inputs.Image)) == true)
59 | {
60 | Records[^1].DisplayImage = Inputs.Image?.ToBitmapSource();
61 | }
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/ViewModels/ImageFilterViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp;
3 | using OpenCvSharp.WpfExtensions;
4 | using System.Collections.ObjectModel;
5 | using VisionProcess.Core.Attributes;
6 | using VisionProcess.Core.Strings;
7 | using VisionProcess.Core.ToolBase;
8 | using VisionProcess.Tools.Models;
9 |
10 | namespace VisionProcess.Tools.ViewModels
11 | {
12 | [DefaultToolConnector(true, "Image", "Inputs.Image")]
13 | [DefaultToolConnector(false, "Image", "Outputs.Image")]
14 | public class ImageFilterViewModel : OperatorBase
15 | {
16 | public ImageFilterViewModel() : base()
17 | {
18 | Init();
19 | Inputs.PropertyChanged += Inputs_PropertyChanged;
20 | }
21 |
22 | [JsonConstructor]
23 | public ImageFilterViewModel(ImageFilterInputs inputs, ImageFilterOutputs outputs, GraphicsEmpty graphics, RunStatus runStatus)
24 | : base(inputs, outputs, graphics, runStatus)
25 | {
26 | Inputs.PropertyChanged += Inputs_PropertyChanged;
27 | }
28 |
29 | protected override bool InternalExecute(out string message)
30 | {
31 | if (Inputs.Image is null)
32 | {
33 | message = "Input image can not be null";
34 | return false;
35 | }
36 | Outputs.Image ??= new Mat();
37 | switch (Inputs.FilterType)
38 | {
39 | case FilterTypes.NormalizedBox:
40 | Outputs.Image = Inputs.Image.Blur(new Size(Inputs.KernelWidth, Inputs.KernelHeight), borderType: Inputs.BorderType);
41 | //Cv2.Blur(Inputs.Image, Outputs.Image, new Size(Inputs.KernelWidth, Inputs.KernelHeight), borderType: Inputs.BorderType);
42 | break;
43 |
44 | case FilterTypes.Median:
45 | Outputs.Image = Inputs.Image.MedianBlur(Inputs.KernelSize);
46 | //Cv2.MedianBlur(Inputs.Image, Outputs.Image, Inputs.KernelSize);
47 | break;
48 |
49 | case FilterTypes.Gaussian:
50 | Outputs.Image = Inputs.Image.GaussianBlur(new Size(Inputs.KernelWidth, Inputs.KernelHeight), Inputs.SigmaX, Inputs.SigmaY, borderType: Inputs.BorderType);
51 | //Cv2.GaussianBlur(Inputs.Image, Outputs.Image, new Size(Inputs.KernelWidth, Inputs.KernelHeight), Inputs.SigmaX, Inputs.SigmaY, borderType: Inputs.BorderType);
52 | break;
53 |
54 | case FilterTypes.Bilateral:
55 | Outputs.Image = Inputs.Image.BilateralFilter(Inputs.Diameter, Inputs.SigmaColor, Inputs.SigmaSpace, borderType: Inputs.BorderType);
56 | //Cv2.BilateralFilter(Inputs.Image, Outputs.Image, Inputs.Diameter, Inputs.SigmaColor, Inputs.SigmaSpace, borderType: Inputs.BorderType);
57 | break;
58 |
59 | default:
60 | break;
61 | }
62 |
63 | Records[0].DisplayImage = Outputs.Image.ToBitmapSource();
64 | message = Strings.Success;
65 | return true;
66 | }
67 |
68 | private void Init()
69 | {
70 | Records.Add(new() { Title = Strings.OutputImage });
71 | Records.Add(new() { Title = Strings.InputImage });
72 | }
73 |
74 | private void Inputs_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
75 | {
76 | if (e.PropertyName?.Equals(nameof(Inputs.Image)) == true)
77 | {
78 | Records[^1].DisplayImage = Inputs.Image?.ToBitmapSource();
79 | }
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/ViewModels/ImageThresholdViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using OpenCvSharp.WpfExtensions;
3 | using System.Collections.ObjectModel;
4 | using System.Drawing;
5 | using VisionProcess.Core.Attributes;
6 | using VisionProcess.Core.Strings;
7 | using VisionProcess.Core.ToolBase;
8 | using VisionProcess.Tools.Models;
9 |
10 | namespace VisionProcess.Tools.ViewModels
11 | {
12 | [DefaultToolConnector(true, "Image", "Inputs.Image")]
13 | [DefaultToolConnector(true, "ThresholdValue", "Inputs.ThresholdValue")]
14 | [DefaultToolConnector(true, "MaximumValue", "Inputs.MaximumValue")]
15 | [DefaultToolConnector(false, "Image", "Outputs.Image")]
16 | public class ImageThresholdViewModel : OperatorBase
17 | {
18 | public ImageThresholdViewModel() : base()
19 | {
20 | Init();
21 | Inputs.PropertyChanged += Inputs_PropertyChanged;
22 | }
23 |
24 | [JsonConstructor]
25 | public ImageThresholdViewModel(ImageThresholdInputs inputs, ImageThresholdOutputs outputs, GraphicsEmpty graphics, RunStatus runStatus)
26 | : base(inputs, outputs, graphics, runStatus)
27 | {
28 | Inputs.PropertyChanged += Inputs_PropertyChanged;
29 | }
30 |
31 | private void Inputs_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
32 | {
33 | if (e.PropertyName?.Equals(nameof(Inputs.Image)) == true)
34 | {
35 | Records[^1].DisplayImage = Inputs.Image?.ToBitmapSource();
36 | }
37 | }
38 |
39 | protected override bool InternalExecute(out string message)
40 | {
41 | if (Inputs.Image is null)
42 | {
43 | message = "Input image can not be null";
44 | return false;
45 | }
46 | Outputs.Image = Inputs.Image.Threshold(Inputs.ThresholdValue, Inputs.MaximumValue, Inputs.ThresholdType);
47 | //Cv2.Threshold(Inputs.Image, Outputs.Image, Inputs.ThresholdValue, Inputs.MaximumValue, Inputs.ThresholdType);
48 |
49 | Records[0].DisplayImage = Outputs.Image.ToBitmapSource();
50 |
51 | message = Strings.Success;
52 | return true;
53 | }
54 |
55 | private void Init()
56 | {
57 | Records.Add(new() { Title = Strings.OutputImage });
58 | Records.Add(new() { Title = Strings.InputImage });
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Views/AcquireImageView.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/VisionProcess.Tools/Views/AcquireImageView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace VisionProcess.Tools.Views
4 | {
5 | ///
6 | /// AcquireImageView.xaml 的交互逻辑
7 | ///
8 | public partial class AcquireImageView : UserControl
9 | {
10 | public AcquireImageView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Views/ColorConvertView.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/VisionProcess.Tools/Views/ColorConvertView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace VisionProcess.Tools.Views
4 | {
5 | ///
6 | /// ColorConvertView.xaml 的交互逻辑
7 | ///
8 | public partial class ColorConvertView : UserControl
9 | {
10 | public ColorConvertView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Views/ImageFilterView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace VisionProcess.Tools.Views
4 | {
5 | ///
6 | /// ImageFilterView.xaml 的交互逻辑
7 | ///
8 | public partial class ImageFilterView : UserControl
9 | {
10 | public ImageFilterView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/Views/ImageThresholdView.xaml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
64 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/VisionProcess.Tools/Views/ImageThresholdView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace VisionProcess.Tools.Views
4 | {
5 | ///
6 | /// ImageThresholdView.xaml 的交互逻辑
7 | ///
8 | public partial class ImageThresholdView : UserControl
9 | {
10 | public ImageThresholdView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess.Tools/VisionProcess.Tools.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0-windows7.0
5 | enable
6 | true
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/VisionProcess.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33516.290
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisionProcess.Core", "VisionProcess.Core\VisionProcess.Core.csproj", "{C29C061E-FA53-48BB-96F4-B960A7DDBA8D}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisionProcess", "VisionProcess\VisionProcess.csproj", "{2A919031-4FB2-42DC-AF45-792BAD85C484}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisionProcess.Tools", "VisionProcess.Tools\VisionProcess.Tools.csproj", "{AB57E0B8-7FA9-4EDB-9857-B2E0A07E3874}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisionProcess.Controls", "VisionProcess.Controls\VisionProcess.Controls.csproj", "{7BCA0146-6E5D-43DC-921D-6AD7AD98F386}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E1856535-05DB-491F-AD61-02F8ACF67A77}"
15 | ProjectSection(SolutionItems) = preProject
16 | C:\Users\yoiri\source\repos\ImageDifferenceDetection\.csharpierrc.json = C:\Users\yoiri\source\repos\ImageDifferenceDetection\.csharpierrc.json
17 | C:\Users\yoiri\source\repos\ImageDifferenceDetection\.editorconfig = C:\Users\yoiri\source\repos\ImageDifferenceDetection\.editorconfig
18 | EndProjectSection
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {C29C061E-FA53-48BB-96F4-B960A7DDBA8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {C29C061E-FA53-48BB-96F4-B960A7DDBA8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {C29C061E-FA53-48BB-96F4-B960A7DDBA8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {C29C061E-FA53-48BB-96F4-B960A7DDBA8D}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {2A919031-4FB2-42DC-AF45-792BAD85C484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {2A919031-4FB2-42DC-AF45-792BAD85C484}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {2A919031-4FB2-42DC-AF45-792BAD85C484}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {2A919031-4FB2-42DC-AF45-792BAD85C484}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {AB57E0B8-7FA9-4EDB-9857-B2E0A07E3874}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {AB57E0B8-7FA9-4EDB-9857-B2E0A07E3874}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {AB57E0B8-7FA9-4EDB-9857-B2E0A07E3874}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {AB57E0B8-7FA9-4EDB-9857-B2E0A07E3874}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {7BCA0146-6E5D-43DC-921D-6AD7AD98F386}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {7BCA0146-6E5D-43DC-921D-6AD7AD98F386}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {7BCA0146-6E5D-43DC-921D-6AD7AD98F386}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {7BCA0146-6E5D-43DC-921D-6AD7AD98F386}.Release|Any CPU.Build.0 = Release|Any CPU
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | GlobalSection(ExtensibilityGlobals) = postSolution
47 | SolutionGuid = {6BF01FD4-8280-4353-992F-622872793872}
48 | EndGlobalSection
49 | EndGlobal
50 |
--------------------------------------------------------------------------------
/VisionProcess/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/VisionProcess/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Reflection;
9 | using System.Runtime.InteropServices;
10 | using System.Threading;
11 | using System.Windows;
12 | using System.Windows.Threading;
13 | using VisionProcess.Core.Helpers;
14 | using VisionProcess.Core.ToolBase;
15 | using VisionProcess.Services;
16 | using VisionProcess.ViewModels;
17 |
18 | namespace VisionProcess
19 | {
20 | ///
21 | /// Interaction logic for App.xaml
22 | ///
23 | public partial class App : Application
24 | {
25 | private static Mutex? appMutex;
26 |
27 | public App()
28 | {
29 | this.DispatcherUnhandledException += App_DispatcherUnhandledException;
30 |
31 | string lang = System.Globalization.CultureInfo.CurrentCulture.Name;
32 | //lang = "ja-jp";
33 | Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(lang); ;
34 | Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(lang); ;
35 | InfoService.Instance.ToolViewModelTypes = GetToolViewModels(AssemblyReflectionHelper.GetAllReferencedAssemblies());
36 | Services = ConfigureServices();
37 | InfoService.Instance.Services = Services;
38 | this.InitializeComponent();
39 | }
40 |
41 | ///
42 | /// Gets the current instance in use
43 | ///
44 | public new static App Current => (App)Application.Current;
45 |
46 | ///
47 | /// Gets the instance to resolve application services.
48 | ///
49 | public IServiceProvider Services { get; }
50 |
51 | [DllImport("User32.dll", EntryPoint = "FindWindow")]
52 | public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
53 |
54 | [DllImport("User32.dll", CharSet = CharSet.Unicode, EntryPoint = "FlashWindow")]
55 | public static extern void FlashWindow(IntPtr hwnd, bool bInvert);
56 |
57 | //查找,启动可能会慢
58 | public static IEnumerable GetToolViewModels(IEnumerable assemblies)
59 | {
60 | List viewModels = new List();
61 | foreach (var asm in assemblies)
62 | {
63 | var types = asm.GetTypes().Where(t => t.IsAbstract == false && t.IsAssignableTo(typeof(IOperator)));
64 | viewModels.AddRange(types);
65 | }
66 | return viewModels;
67 | }
68 |
69 | [DllImport("User32.DLL")]
70 | public static extern bool SetForegroundWindow(IntPtr hWnd);
71 |
72 | protected override void OnExit(ExitEventArgs e)
73 | {
74 | var mainViewModel = Services.GetService()
75 | ?? throw new ArgumentNullException(nameof(MainViewModel));
76 |
77 | if (File.Exists(@"configs\mainViewModel.config"))
78 | {
79 | // serialize JSON to a string and then write string to a file
80 | JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings()
81 | {
82 | NullValueHandling = NullValueHandling.Ignore,
83 | TypeNameHandling = TypeNameHandling.Auto,
84 | Formatting = Formatting.Indented,
85 | DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
86 | DateParseHandling = DateParseHandling.DateTime
87 | };
88 | File.WriteAllText(@"configs\mainViewModel.config", JsonConvert.SerializeObject(mainViewModel, jsonSerializerSettings));
89 | }
90 | else
91 | {
92 | // serialize JSON directly to a file
93 | using (StreamWriter file = File.CreateText(@"configs\mainViewModel.config"))
94 | {
95 | JsonSerializer serializer = new()
96 | {
97 | NullValueHandling = NullValueHandling.Ignore,
98 | TypeNameHandling = TypeNameHandling.Auto,
99 | Formatting = Formatting.Indented,
100 | DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
101 | DateParseHandling = DateParseHandling.DateTime
102 | };
103 | serializer.Serialize(file, mainViewModel);
104 | }
105 | }
106 | base.OnExit(e);
107 | }
108 |
109 | protected override void OnStartup(StartupEventArgs e)
110 | {
111 | System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
112 | CheckMutex(e);
113 | }
114 |
115 | ///
116 | /// Configures the services for the application.
117 | ///
118 | private static IServiceProvider ConfigureServices()
119 | {
120 | if (!Directory.Exists(@"configs")) //如果文件夹不存在则创建
121 | {
122 | Directory.CreateDirectory(@"configs");
123 | }
124 |
125 | var services = new ServiceCollection();
126 | if (File.Exists(@"configs\mainViewModel.config"))
127 | {
128 | // serialize JSON to a string and then write string to a file
129 | var mainViewModel = JsonConvert.DeserializeObject(File.ReadAllText(@"configs\mainViewModel.config"), new JsonSerializerSettings
130 | {
131 | NullValueHandling = NullValueHandling.Ignore,
132 | TypeNameHandling = TypeNameHandling.Auto,
133 | Formatting = Formatting.Indented,
134 | DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
135 | DateParseHandling = DateParseHandling.DateTime
136 | });
137 | if (mainViewModel is null)
138 | throw new ArgumentNullException();
139 | services.AddSingleton(o => mainViewModel);
140 | }
141 | else
142 | {
143 | services.AddSingleton();
144 | }
145 | services.AddTransient();
146 |
147 | foreach (var itemType in InfoService.Instance.ToolViewModelTypes!)//遍历所有类型进行查找
148 | {
149 | services.AddTransient(itemType);
150 | //list.Add(itemType.Name.Replace("ViewModel", string.Empty));
151 | }
152 |
153 | return services.BuildServiceProvider();
154 | }
155 |
156 | [DllImport("User32.dll")]
157 | private static extern int ShowWindow(IntPtr hwnd, uint nCmdShow);
158 |
159 | private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
160 | {
161 | // 防止默认的异常处理
162 | e.Handled = true;
163 |
164 | // 显示错误消息
165 | MessageBox.Show($"An unexpected exception has occurred: {e.Exception.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
166 | }
167 | private void CheckMutex(StartupEventArgs e)
168 | {
169 | Process currentProc = Process.GetCurrentProcess();
170 | appMutex = new System.Threading.Mutex(true, currentProc.ProcessName, out bool createdNew);
171 | if (createdNew)
172 | {
173 | base.OnStartup(e);
174 | }
175 | else
176 | {
177 | var proc = Process.GetProcessesByName(currentProc.ProcessName)
178 | .FirstOrDefault(x => x.Id != currentProc.Id);
179 | if (proc != null)
180 | {
181 | //这里不作用。PID是正确的
182 | //IntPtr handle = proc.Handle;
183 | //这里也能起作用,也是用的是主窗口名称
184 | IntPtr handle = proc.MainWindowHandle;
185 | //var ffi = Create_FLASHWINFO(handle, FlashWindowFlag.FLASHW_TIMERNOFG, 500, 5000);
186 | //FlashWindowEx(ref ffi);
187 | ShowWindow(handle, 9);
188 | SetForegroundWindow(handle);
189 | }
190 |
191 | //var hwnd = FindWindow(null, currentProc.ProcessName);//找string的窗口
192 | ////var fi = User32Api.Create_FLASHWINFO(hwnd, FlashWindowFlag.FLASHW_TIMERNOFG, 1, 2000);
193 | ////FlashWindowEx(ref fi);
194 | //// FlashWindow(hwnd, true);//Flash 会有点慢
195 | //ShowWindow(hwnd, 9);
196 | //SetForegroundWindow(hwnd);//使用的窗口名称
197 | //Process.GetCurrentProcess().Kill();
198 | //App.Current.Shutdown();
199 | Environment.Exit(0);
200 | }
201 | }
202 |
203 | //[DllImport("User32.dll")]
204 | //[return: MarshalAs(UnmanagedType.Bool)]
205 | //public static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
206 | }
207 | }
--------------------------------------------------------------------------------
/VisionProcess/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
--------------------------------------------------------------------------------
/VisionProcess/Extensions/OperationsExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Windows;
3 | using VisionProcess.Models;
4 |
5 | namespace VisionProcess.Extensions
6 | {
7 | public static class OperationsExtensions
8 | {
9 | public static Rect GetBoundingBox(this IEnumerable nodes, double padding = 0, int gridCellSize = 15)
10 | {
11 | var minX = double.MaxValue;
12 | var minY = double.MaxValue;
13 |
14 | var maxX = double.MinValue;
15 | var maxY = double.MinValue;
16 |
17 | const int width = 200; //node.Width
18 | const int height = 100; //node.Height
19 |
20 | foreach (var node in nodes)
21 | {
22 | if (node.Location.X < minX)
23 | {
24 | minX = node.Location.X;
25 | }
26 |
27 | if (node.Location.Y < minY)
28 | {
29 | minY = node.Location.Y;
30 | }
31 |
32 | var sizeX = node.Location.X + width;
33 | if (sizeX > maxX)
34 | {
35 | maxX = sizeX;
36 | }
37 |
38 | var sizeY = node.Location.Y + height;
39 | if (sizeY > maxY)
40 | {
41 | maxY = sizeY;
42 | }
43 | }
44 |
45 | var result = new Rect(minX - padding, minY - padding, maxX - minX + padding * 2, maxY - minY + padding * 2);
46 | result.X = (int)result.X / gridCellSize * gridCellSize;
47 | result.Y = (int)result.Y / gridCellSize * gridCellSize;
48 | return result;
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/VisionProcess/Models/ConnectionModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 |
3 | namespace VisionProcess.Models
4 | {
5 | public class ConnectionModel : ObservableObject
6 | {
7 | private ConnectorModel? input;
8 |
9 | public ConnectorModel? Input
10 | {
11 | get => input;
12 | set => SetProperty(ref input, value);
13 | }
14 |
15 | private ConnectorModel? output;
16 |
17 | public ConnectorModel? Output
18 | {
19 | get => output;
20 | set => SetProperty(ref output, value);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/VisionProcess/Models/ConnectorModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using VisionProcess.Core.Extensions;
9 | using VisionProcess.Core.Helpers;
10 |
11 | namespace VisionProcess.Models
12 | {
13 | public class ConnectorModel : ObservableObject
14 | {
15 | private readonly bool isInput;
16 |
17 | private readonly OperationModel? owner;
18 | private readonly Guid ownerId;
19 | private readonly string valueName;
20 | private Point anchor;
21 | private bool isConnected = false;
22 | private string title;
23 | private string valuePath;
24 | private Type valueType;
25 |
26 | public ConnectorModel(string title, Type valueType, string valuePath, bool isInput, Guid ownerId, OperationModel owner)
27 | {
28 | this.title = title;
29 | this.valueType = valueType;
30 | this.valuePath = valuePath;
31 | this.isInput = isInput;
32 | this.ownerId = ownerId;
33 | valueName = valuePath.Split(".")[^1];
34 | this.owner = owner;
35 | if (this.owner.Operator == null)
36 | throw new ArgumentNullException(nameof(ConnectorModel.owner.Operator));
37 | }
38 |
39 | [JsonConstructor]
40 | public ConnectorModel(string title, Type valueType, string valuePath, bool isInput, Guid ownerId)
41 | {
42 | //由于反序列化时会重新 new,所以只需基础信息
43 | this.title = title;
44 | this.valueType = valueType;
45 | this.valuePath = valuePath;
46 | this.isInput = isInput;
47 | this.ownerId = ownerId;
48 | valueName = valuePath.Split(".")[^1];
49 | }
50 |
51 | public Point Anchor
52 | {
53 | get => anchor;
54 | set => SetProperty(ref anchor, value);
55 | }
56 |
57 | [JsonIgnore]
58 | public bool IsAssigned { get; set; } = false;
59 |
60 | public bool IsConnected
61 | {
62 | get => isConnected;
63 | set
64 | {
65 | SetProperty(ref isConnected, value);
66 | if (value) OnPropertyChanged(nameof(Value));
67 | }
68 | }
69 |
70 | public bool IsInput
71 | {
72 | get => isInput;
73 | }
74 |
75 | [JsonIgnore]
76 | public OperationModel Owner => owner!;
77 |
78 | public Guid OwnerId
79 | {
80 | get => ownerId;
81 | }
82 |
83 | public string Title
84 | {
85 | get => title;
86 | set => SetProperty(ref title, value);
87 | }
88 |
89 | [JsonIgnore]
90 | public object? Value
91 | {
92 | get
93 | {
94 | if (owner is null || owner.Operator is null)
95 | {
96 | return null;
97 | }
98 | return PropertyReflectionHelper.GetValue(owner.Operator, valuePath);
99 | }
100 | }
101 |
102 | [JsonIgnore]
103 | public List ValueObservers { get; } = new();
104 |
105 | public string ValuePath
106 | {
107 | get { return valuePath; }
108 | protected set { SetProperty(ref valuePath, value); }
109 | }
110 |
111 | [JsonIgnore]
112 | public Type ValueType
113 | {
114 | get => valueType;
115 | protected set => SetProperty(ref valueType, value);
116 | }
117 |
118 | public async Task SetInputValue(object? value)
119 | {
120 | if (!isInput || owner is null || owner.Operator is null)
121 | return;
122 | IsAssigned = true;
123 | PropertyReflectionHelper.TrySetValue(owner.Operator, ValuePath, value);
124 | //当全部已经链接的Inputs被赋值后才运行
125 | var connectedInputsCount = owner.Inputs.Count(x => x.IsConnected);
126 | var assignedInputsCount = owner.Inputs.Count(x => x.IsAssigned);
127 | if (connectedInputsCount == assignedInputsCount)
128 | {
129 | await owner.Operator.ExecuteAsync();
130 | owner.Inputs.ForEach(x => x.IsAssigned = false);
131 | }
132 | }
133 | }
134 | }
--------------------------------------------------------------------------------
/VisionProcess/Models/OperationGroupModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace VisionProcess.Models
4 | {
5 | public class OperationGroupModel : OperationModel
6 | {
7 | private Size _size;
8 |
9 | public Size GroupSize
10 | {
11 | get => _size;
12 | set => SetProperty(ref _size, value);
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess/Models/OperationModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using Newtonsoft.Json;
4 | using System;
5 | using System.Linq;
6 | using System.Windows;
7 | using VisionProcess.Core.Attributes;
8 | using VisionProcess.Core.Helpers;
9 | using VisionProcess.Core.Mvvm;
10 | using VisionProcess.Core.ToolBase;
11 | using VisionProcess.Services;
12 |
13 | namespace VisionProcess.Models
14 | {
15 | public partial class OperationModel : ObservableObject
16 | {
17 | private readonly Guid id;
18 | private IOperator? @operator;
19 | private bool isSelected = false;
20 | private Point location;
21 | private Size size;
22 |
23 | public OperationModel()
24 | {
25 | id = Guid.NewGuid();
26 | Init();
27 | }
28 |
29 | [JsonConstructor]
30 | public OperationModel(IOperator @operator, NodifyObservableCollection inputs,
31 | NodifyObservableCollection outputs, Point location, bool isSelected, Size size, Guid id)
32 | {
33 | this.@operator = @operator;
34 | this.@operator.Executed += Operation_Executed;
35 | this.isSelected = isSelected;
36 | this.location = location;
37 | this.size = size;
38 | this.id = id;
39 |
40 | foreach (var input in inputs)
41 | {
42 | var type = PropertyReflectionHelper.GetType(@operator, input.ValuePath)!;
43 | Inputs.Add(new ConnectorModel(input.Title, type,
44 | input.ValuePath, input.IsInput, input.OwnerId, this)
45 | { Anchor = input.Anchor, IsConnected = input.IsConnected });
46 | }
47 | foreach (var output in outputs)
48 | {
49 | var type = PropertyReflectionHelper.GetType(@operator, output.ValuePath)!;
50 | Outputs.Add(new ConnectorModel(output.Title, type,
51 | output.ValuePath, output.IsInput, output.OwnerId, this)
52 | { Anchor = output.Anchor, IsConnected = output.IsConnected });
53 | }
54 | Init();
55 | }
56 |
57 | public event EventHandler? OperatorExecuted;
58 |
59 | public Guid Id => id;
60 |
61 | public NodifyObservableCollection Inputs { get; } = [];
62 |
63 | public bool IsSelected
64 | {
65 | get => isSelected;
66 | set => SetProperty(ref isSelected, value);
67 | }
68 |
69 | public Point Location
70 | {
71 | get => location;
72 | set => SetProperty(ref location, value);
73 | }
74 |
75 | public IOperator? Operator
76 | {
77 | get => @operator;
78 | init
79 | {
80 | if (@operator != null)
81 | @operator.Executed -= Operation_Executed;
82 | SetProperty(ref @operator, value);
83 | if (value is null)
84 | {
85 | Inputs.Clear();
86 | Outputs.Clear();
87 | return;
88 | }
89 | value.Executed += Operation_Executed;
90 | value.Name = value.GetType().Name.Replace("ViewModel", "");
91 | var attributes = (DefaultToolConnectorAttribute[])value.GetType().GetCustomAttributes(typeof(DefaultToolConnectorAttribute), false);
92 | foreach (var item in attributes)
93 | {
94 | var type = PropertyReflectionHelper.GetType(value, item.Path) ?? throw new ArgumentException("Error, DefaultToolConnectorAttribute setting error");
95 | if (item.IsInput)
96 | {
97 | Inputs.Add(new ConnectorModel(item.Title, type, item.Path, true, Id, this));
98 | }
99 | else
100 | {
101 | Outputs.Add(new ConnectorModel(item.Title, type, item.Path, false, Id, this));
102 | }
103 | }
104 | }
105 | }
106 |
107 |
108 |
109 | public NodifyObservableCollection Outputs { get; } = [];
110 |
111 | public Size Size
112 | {
113 | get => size;
114 | set => SetProperty(ref size, value);
115 | }
116 |
117 | [property: JsonIgnore]
118 | [RelayCommand]
119 | private void AddIO()
120 | {
121 | WindowDialogService.OpenIOConnectorDialog(this);
122 | }
123 |
124 | private void Init()
125 | {
126 | Inputs.WhenAdded(x =>
127 | {
128 | if (Inputs.Where(y => y.ValuePath == x.ValuePath).Count() > 1)
129 | Inputs.Remove(x);
130 | });
131 | Outputs.WhenAdded(x =>
132 | {
133 |
134 | if (Outputs.Where(y => y.ValuePath == x.ValuePath).Count() > 1)
135 | Outputs.Remove(x);
136 | });
137 | }
138 |
139 | private void Operation_Executed(object? sender, EventArgs e)
140 | {
141 | OperatorExecuted?.Invoke(this, e);
142 | }
143 | }
144 | }
--------------------------------------------------------------------------------
/VisionProcess/Models/PendingConnectionModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using System.Windows;
3 |
4 | namespace VisionProcess.Models
5 | {
6 | public class PendingConnectionModel : ObservableObject
7 | {
8 | private ConnectorModel source = default!;
9 |
10 | public ConnectorModel Source
11 | {
12 | get => source;
13 | set => SetProperty(ref source, value);
14 | }
15 |
16 | private ConnectorModel? target;
17 |
18 | public ConnectorModel? Target
19 | {
20 | get => target;
21 | set => SetProperty(ref target, value);
22 | }
23 |
24 | private bool isVisible;
25 |
26 | public bool IsVisible
27 | {
28 | get => isVisible;
29 | set => SetProperty(ref isVisible, value);
30 | }
31 |
32 | private Point targetLocation;
33 |
34 | public Point TargetLocation
35 | {
36 | get => targetLocation;
37 | set => SetProperty(ref targetLocation, value);
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/VisionProcess/Services/InfoService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace VisionProcess.Services
8 | {
9 | public sealed class InfoService
10 | {
11 | private InfoService()
12 | {
13 | }
14 | private static readonly InfoService instance = new();
15 | public static InfoService Instance
16 | {
17 | get
18 | {
19 | return instance;
20 | }
21 | }
22 |
23 | public IEnumerable? ToolViewModelTypes { get; set; }
24 | public IServiceProvider? Services { get; set; }
25 |
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/VisionProcess/Services/WindowDialogService.cs:
--------------------------------------------------------------------------------
1 | using MahApps.Metro.Controls;
2 | using System.Windows.Controls;
3 | using System.Windows.Media;
4 | using System.Windows;
5 | using VisionProcess.Controls.UserControls;
6 | using VisionProcess.Models;
7 | using VisionProcess.Views;
8 | using VisionProcess.ViewModels;
9 |
10 | namespace VisionProcess.Services
11 | {
12 | public static class WindowDialogService
13 | {
14 |
15 | public static void OpenIOConnectorDialog(OperationModel operationModel)
16 | {
17 | MetroWindow window = new()
18 | {
19 | Width = 800,
20 | Height = 600,
21 | Title = operationModel.Operator!.Name,
22 | ResizeMode = ResizeMode.CanResizeWithGrip,
23 | TitleCharacterCasing = CharacterCasing.Normal,
24 | Content = new IOConnectorView() { DataContext = new IOConnectorViewModel(operationModel) }
25 | };
26 | //var iOConnectorViewModel =new IOConnectorViewModel(operationModel);
27 | //window.Content = new IOConnectorView() { DataContext = iOConnectorViewModel };
28 | window.ShowDialog();
29 | }
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/VisionProcess/ViewModels/EditorViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using Newtonsoft.Json;
4 | using System;
5 | using System.Xml.Linq;
6 | using VisionProcess.Models;
7 |
8 | namespace VisionProcess.ViewModels
9 | {
10 | public partial class EditorViewModel : ObservableObject
11 | {
12 | private string? name;
13 |
14 | private ProcessModel process;
15 |
16 | public EditorViewModel()
17 | {
18 | process = new ProcessModel();
19 | Id = Guid.NewGuid();
20 | }
21 |
22 | [JsonConstructor]
23 | public EditorViewModel(ProcessModel process, Guid id, string? name)
24 | {
25 | this.process = process;
26 | Id = id;
27 | this.name = name;
28 | }
29 |
30 | public Guid Id { get; }
31 |
32 | public string? Name
33 | {
34 | get => name;
35 | set => SetProperty(ref name, value);
36 | }
37 |
38 | public EditorViewModel? Parent { get; set; }
39 |
40 | public ProcessModel Process
41 | {
42 | get => process;
43 | set => SetProperty(ref process, value);
44 | }
45 |
46 | [property: JsonIgnore]
47 | [RelayCommand]
48 | private void Disconnect(ConnectionModel connection)
49 | {
50 | connection.Input!.IsConnected = false;
51 | connection.Output!.IsConnected = false;
52 | Process.Connections.Remove(connection);
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/VisionProcess/ViewModels/MainViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using Newtonsoft.Json;
4 | using System;
5 | using System.Linq;
6 | using VisionProcess.Core.Extensions;
7 | using VisionProcess.Core.Mvvm;
8 |
9 | namespace VisionProcess.ViewModels
10 | {
11 | public partial class MainViewModel : ObservableObject
12 | {
13 | public MainViewModel()
14 | {
15 | Editors = [];
16 | Init();
17 | Editors.Add(new EditorViewModel
18 | {
19 | Name = $"Editor {Editors.Count + 1}"
20 | });
21 | }
22 |
23 | [JsonConstructor]
24 | public MainViewModel(NodifyObservableCollection editors,
25 | bool autoSelectNewEditor, EditorViewModel? selectedEditor)
26 | {
27 | Editors = editors;
28 | this.autoSelectNewEditor = autoSelectNewEditor;
29 | if (selectedEditor is not null)
30 | {
31 | this.selectedEditor = editors.First(x => x.Id == selectedEditor.Id);
32 | }
33 | Init();
34 | }
35 |
36 | private void Init()
37 | {
38 | Editors.WhenAdded((editor) =>
39 | {
40 | if (AutoSelectNewEditor || Editors.Count == 1)
41 | {
42 | SelectedEditor = editor;
43 | }
44 | })
45 | .WhenRemoved((editor) =>
46 | {
47 | var childEditors = Editors.Where(ed => ed.Parent == editor).ToArray();
48 | childEditors.ForEach(ed => Editors.Remove(ed));
49 | });
50 | }
51 |
52 | #region Properties
53 |
54 | [ObservableProperty]
55 | private bool autoSelectNewEditor = true;
56 |
57 | [ObservableProperty]
58 | private EditorViewModel? selectedEditor;
59 |
60 | public NodifyObservableCollection Editors { get; }
61 |
62 | #endregion Properties
63 |
64 | #region Commands
65 |
66 | [property: JsonIgnore]
67 | [RelayCommand]
68 | private void AddEditor()
69 | {
70 | Editors.Add(new EditorViewModel
71 | {
72 | Name = $"Editor {Editors.Count + 1}"
73 | });
74 | SelectedEditor = Editors[^1];
75 | }
76 |
77 | private bool CanCloseEditor()
78 | {
79 | return Editors.Count > 0 && SelectedEditor != null;
80 | }
81 |
82 | [property: JsonIgnore]
83 | [RelayCommand(CanExecute = nameof(CanCloseEditor))]
84 | private void CloseEditor(Guid id)
85 | {
86 | Editors.RemoveOne(editor => editor.Id == id);
87 | }
88 | #endregion Commands
89 | }
90 | }
--------------------------------------------------------------------------------
/VisionProcess/ViewModels/OperationsMenuViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Windows;
7 | using Newtonsoft.Json;
8 | using VisionProcess.Core.ToolBase;
9 | using VisionProcess.Models;
10 | using VisionProcess.Services;
11 |
12 | namespace VisionProcess.ViewModels
13 | {
14 | public partial class OperationsMenuViewModel : ObservableObject
15 | {
16 | public OperationsMenuViewModel(ProcessModel processModel)
17 | {
18 | List list = new();
19 | foreach (var itemType in InfoService.Instance.ToolViewModelTypes!)//遍历所有类型进行查找
20 | {
21 | list.Add(itemType.Name.Replace("ViewModel", string.Empty));
22 | }
23 | AvailableOperations = list;
24 | this.processModel = processModel;
25 | }
26 |
27 | [ObservableProperty]
28 | private Point _location;
29 |
30 | [ObservableProperty]
31 | private bool _isVisible;
32 |
33 | private readonly ProcessModel processModel;
34 |
35 | public IEnumerable AvailableOperations { get; }
36 |
37 | public void OpenAt(Point targetLocation)
38 | {
39 | Close();
40 | Location = targetLocation;
41 | IsVisible = true;
42 | }
43 |
44 | public void Close()
45 | {
46 | IsVisible = false;
47 | }
48 |
49 | [property: JsonIgnore]
50 | [RelayCommand]
51 | private void CreateOperation(string operationName)
52 | {
53 | //前提,需要规范命名
54 | var type = InfoService.Instance.ToolViewModelTypes!.FirstOrDefault(t => t.Name == operationName + "ViewModel") ??
55 | throw new ArgumentNullException($"{operationName} + ViewModel");
56 |
57 | //var type = App.ToolsAssembly.GetType("VisionProcess.Tools.ViewModels." + operationName + "ViewModel");
58 |
59 | var instance = InfoService.Instance.Services!.GetService(type);
60 | //var instance = Activator.CreateInstance(type!);
61 |
62 | processModel.Operations.Add(new OperationModel() { Operator = (IOperator)instance!, Location = Location });
63 | IsVisible = false;
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/VisionProcess/Views/EditorView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Nodify;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Input;
5 | using VisionProcess.Models;
6 |
7 | namespace VisionProcess.Views
8 | {
9 | ///
10 | /// EditorView.xaml 的交互逻辑
11 | ///
12 | public partial class EditorView : UserControl
13 | {
14 | public EditorView()
15 | {
16 | InitializeComponent();
17 | EventManager.RegisterClassHandler(typeof(NodifyEditor), MouseLeftButtonDownEvent, new MouseButtonEventHandler(CloseOperationsMenu));
18 | EventManager.RegisterClassHandler(typeof(ItemContainer), ItemContainer.DragStartedEvent, new RoutedEventHandler(CloseOperationsMenu));
19 | EventManager.RegisterClassHandler(typeof(NodifyEditor), MouseRightButtonUpEvent, new MouseButtonEventHandler(OpenOperationsMenu));
20 | }
21 |
22 | private void OpenOperationsMenu(object sender, MouseButtonEventArgs e)
23 | {
24 | if (!e.Handled && e.OriginalSource is NodifyEditor editor && !editor.IsPanning && editor.DataContext is ProcessModel process)
25 | {
26 | e.Handled = true;
27 | process.OperationsMenu.OpenAt(editor.MouseLocation);
28 | }
29 | }
30 |
31 | private void CloseOperationsMenu(object sender, RoutedEventArgs e)
32 | {
33 | ItemContainer? itemContainer = sender as ItemContainer;
34 | NodifyEditor? editor = sender as NodifyEditor ?? itemContainer?.Editor;
35 |
36 | if (!e.Handled && editor?.DataContext is ProcessModel process)
37 | {
38 | process.OperationsMenu.Close();
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/VisionProcess/Views/IOConnectorView.xaml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
58 |
61 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/VisionProcess/Views/IOConnectorView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace VisionProcess.Views
17 | {
18 | ///
19 | /// IOConnectorView.xaml 的交互逻辑
20 | ///
21 | public partial class IOConnectorView : UserControl
22 | {
23 | public IOConnectorView()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/VisionProcess/Views/MainView.xaml:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
28 |
29 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
48 |
50 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
77 |
78 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
94 |
95 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
108 |
109 |
110 |
112 |
113 |
117 |
118 |
129 |
130 |
131 |
132 |
133 |
134 |
138 |
139 |
140 |
141 |
142 |
143 |
146 |
147 |
149 |
150 |
151 |
152 |
165 |
166 |
167 |
169 |
170 |
171 |
172 |
173 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/VisionProcess/Views/MainView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using System;
3 | using System.Runtime.InteropServices;
4 | using VisionProcess.ViewModels;
5 |
6 | namespace VisionProcess.Views
7 | {
8 | ///
9 | /// Interaction logic for MainView.xaml
10 | ///
11 | public partial class MainView
12 | {
13 | public MainView()
14 | {
15 | InitializeComponent();
16 |
17 | this.DataContext = App.Current.Services.GetService();
18 |
19 | //虽然圆角,但影响发光边框。。。。。
20 | //https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-rounded-corners
21 |
22 | //IntPtr hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle();
23 | //var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE;
24 | //var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND; 1
25 | //DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint));
26 |
27 | //还有云母布局。。。
28 | //https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-snap-layout-menu
29 |
30 | //EfficiencyModeUtilities.SetEfficiencyMode(true);
31 | //WindowExtensions.Hide(this, enableEfficiencyMode: true); // default value
32 | //WindowExtensions.Show(this, disableEfficiencyMode: true);// default value
33 | //ic.ForceCreate(enablesEfficiencyMode: true); // default value
34 | }
35 |
36 | // The enum flag for DwmSetWindowAttribute's second parameter, which tells the function what attribute to set.
37 | // Copied from dwmapi.h
38 | public enum DWMWINDOWATTRIBUTE
39 | {
40 | DWMWA_WINDOW_CORNER_PREFERENCE = 33
41 | }
42 |
43 | // The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function
44 | // what value of the enum to set.
45 | // Copied from dwmapi.h
46 | public enum DWM_WINDOW_CORNER_PREFERENCE
47 | {
48 | DWMWCP_DEFAULT = 0,
49 | DWMWCP_DONOTROUND = 1,
50 | DWMWCP_ROUND = 2,
51 | DWMWCP_ROUNDSMALL = 3
52 | }
53 |
54 | // Import dwmapi.dll and define DwmSetWindowAttribute in C# corresponding to the native function.
55 | [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
56 | internal static extern void DwmSetWindowAttribute(IntPtr hwnd,
57 | DWMWINDOWATTRIBUTE attribute,
58 | ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute,
59 | uint cbAttribute);
60 | }
61 | }
--------------------------------------------------------------------------------
/VisionProcess/Views/OperationView.xaml:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
50 |
57 |
58 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
100 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/VisionProcess/Views/OperationView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace VisionProcess.Views
4 | {
5 | ///
6 | /// OperationView.xaml 的交互逻辑
7 | ///
8 | public partial class OperationView : UserControl
9 | {
10 | public OperationView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess/Views/OperationsMenuView.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
19 |
20 |
28 |
29 |
34 |
38 |
39 |
40 |
41 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/VisionProcess/Views/OperationsMenuView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace VisionProcess.Views
4 | {
5 | ///
6 | /// OperationsMenuView.xaml 的交互逻辑
7 | ///
8 | public partial class OperationsMenuView : UserControl
9 | {
10 | public OperationsMenuView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/VisionProcess/VisionProcess.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net8.0-windows7.0
6 | enable
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------