Переглянути джерело

增加配置工具

样式分支
fyf 2 роки тому
джерело
коміт
189d317eae
71 змінених файлів з 6513 додано та 1 видалено
  1. +114
    -0
      BeDesignerSCADA/Adorners/SelectionAdorner.cs
  2. +32
    -0
      BeDesignerSCADA/Adorners/SelectionAlignLine.cs
  3. +9
    -0
      BeDesignerSCADA/App.xaml
  4. +17
    -0
      BeDesignerSCADA/App.xaml.cs
  5. +112
    -0
      BeDesignerSCADA/BeDesignerSCADA.csproj
  6. +31
    -0
      BeDesignerSCADA/BeDesignerSCADA.sln
  7. +53
    -0
      BeDesignerSCADA/Common/PropertyHelper.cs
  8. +902
    -0
      BeDesignerSCADA/Controls/CanvasPanel.cs
  9. +32
    -0
      BeDesignerSCADA/Controls/RunCanvas.xaml
  10. +133
    -0
      BeDesignerSCADA/Controls/RunCanvas.xaml.cs
  11. +36
    -0
      BeDesignerSCADA/Converters/BoolToVisibilityConverter.cs
  12. +28
    -0
      BeDesignerSCADA/Converters/HalfNumberConverter.cs
  13. +31
    -0
      BeDesignerSCADA/Converters/ZoomConverter.cs
  14. +198
    -0
      BeDesignerSCADA/CustomerControls/ArcGauge.cs
  15. +62
    -0
      BeDesignerSCADA/CustomerControls/DigitalNumber.cs
  16. +14
    -0
      BeDesignerSCADA/CustomerControls/GraphArrow.xaml
  17. +56
    -0
      BeDesignerSCADA/CustomerControls/GraphArrow.xaml.cs
  18. +14
    -0
      BeDesignerSCADA/CustomerControls/GraphStar.xaml
  19. +56
    -0
      BeDesignerSCADA/CustomerControls/GraphStar.xaml.cs
  20. +240
    -0
      BeDesignerSCADA/CustomerControls/KnobButton.cs
  21. +372
    -0
      BeDesignerSCADA/CustomerControls/NumberBox.cs
  22. +101
    -0
      BeDesignerSCADA/CustomerControls/StatusLight.cs
  23. +150
    -0
      BeDesignerSCADA/CustomerControls/SwitchButton.cs
  24. +9
    -0
      BeDesignerSCADA/CustomerControls/TheButton.xaml
  25. +77
    -0
      BeDesignerSCADA/CustomerControls/TheButton.xaml.cs
  26. +9
    -0
      BeDesignerSCADA/CustomerControls/TheCheckBox.xaml
  27. +92
    -0
      BeDesignerSCADA/CustomerControls/TheCheckBox.xaml.cs
  28. +9
    -0
      BeDesignerSCADA/CustomerControls/TheComboBox.xaml
  29. +75
    -0
      BeDesignerSCADA/CustomerControls/TheComboBox.xaml.cs
  30. +9
    -0
      BeDesignerSCADA/CustomerControls/TheGroupBox.xaml
  31. +58
    -0
      BeDesignerSCADA/CustomerControls/TheGroupBox.xaml.cs
  32. +9
    -0
      BeDesignerSCADA/CustomerControls/TheImage.xaml
  33. +57
    -0
      BeDesignerSCADA/CustomerControls/TheImage.xaml.cs
  34. +59
    -0
      BeDesignerSCADA/CustomerControls/TheRadioButton.cs
  35. +69
    -0
      BeDesignerSCADA/CustomerControls/TheSlider.cs
  36. +9
    -0
      BeDesignerSCADA/CustomerControls/TheTextBlock.xaml
  37. +55
    -0
      BeDesignerSCADA/CustomerControls/TheTextBlock.xaml.cs
  38. +61
    -0
      BeDesignerSCADA/CustomerControls/TheTextBox.cs
  39. +99
    -0
      BeDesignerSCADA/CustomerControls/TheTimer.cs
  40. +9
    -0
      BeDesignerSCADA/CustomerControls/TheToggleButton.xaml
  41. +96
    -0
      BeDesignerSCADA/CustomerControls/TheToggleButton.xaml.cs
  42. +187
    -0
      BeDesignerSCADA/CustomerControls/WaveProgressBar.cs
  43. BIN
     
  44. BIN
     
  45. BIN
     
  46. +76
    -0
      BeDesignerSCADA/Helper/Config.cs
  47. BIN
     
  48. BIN
     
  49. BIN
     
  50. BIN
     
  51. BIN
     
  52. BIN
     
  53. BIN
     
  54. BIN
     
  55. BIN
     
  56. BIN
     
  57. BIN
     
  58. BIN
     
  59. BIN
     
  60. BIN
     
  61. BIN
     
  62. +296
    -0
      BeDesignerSCADA/MainWindow.xaml
  63. +441
    -0
      BeDesignerSCADA/MainWindow.xaml.cs
  64. +14
    -0
      BeDesignerSCADA/Speical/ControlTypeAttribute.cs
  65. +37
    -0
      BeDesignerSCADA/Speical/ItemsList.cs
  66. +686
    -0
      BeDesignerSCADA/Themes/Styles.xaml
  67. +50
    -0
      BeDesignerSCADA/View/JsEditWindow.xaml
  68. +94
    -0
      BeDesignerSCADA/View/JsEditWindow.xaml.cs
  69. +80
    -0
      BeDesignerSCADA/ViewModel/EventModel.cs
  70. +871
    -0
      BeDesignerSCADA/ViewModel/MainViewModel.cs
  71. +27
    -1
      SmartClient.sln

+ 114
- 0
BeDesignerSCADA/Adorners/SelectionAdorner.cs Переглянути файл

@@ -0,0 +1,114 @@
using BeDesignerSCADA.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace BeDesignerSCADA.Adorners
{
internal class SelectionAdorner : Adorner
{
public SelectionAdorner(UIElement adornedEIeent) : base(adornedEIeent) { }

protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
Rect adornerRect = new Rect(AdornedElement.DesiredSize);
SolidColorBrush renderBrush = Brushes.Transparent;
Pen render = new Pen(new SolidColorBrush(Colors.OrangeRed), 1);
render.DashStyle = new DashStyle(new List<double>() { 4, 2 }, 2);
drawingContext.DrawRectangle(renderBrush, render, new Rect(adornerRect.TopLeft.X, adornerRect.TopLeft.Y, adornerRect.Width, adornerRect.Height));

MouseDown += SelectionAdorner_MouseDown;
MouseMove += SelectionAdorner_MouseMove;
MouseUp += SelectionAdorner_MouseUp;

ContextMenu = FindResource("AdornerRightMenu") as ContextMenu;
Tag = CanvasPanel.GetParentObject<CanvasPanel>(AdornedElement);

this.Focus();
this.SelectionAdorner_MouseDown(this, null);
this.SelectionAdorner_MouseMove(this, null);
}

private void SelectionAdorner_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
ReleaseMouseCapture();
CanvasPanel.GetParentObject<CanvasPanel>(AdornedElement).ClearAlignLine();
}

Point lastPoint = new Point();
double tempX = 0d;
double tempY = 0d;
double movePx = 0d;
private void SelectionAdorner_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
if (lastPoint.X == 0 && lastPoint.Y == 0)
{
return;
}

CaptureMouse();
var nowPoint = Mouse.GetPosition(CanvasPanel.GetParentObject<CanvasPanel>(AdornedElement));
double offsetX = nowPoint.X - lastPoint.X;
double offsetY = nowPoint.Y - lastPoint.Y;
lastPoint = nowPoint;

tempX += offsetX;
tempY += offsetY;

var canvas = CanvasPanel.GetParentObject<CanvasPanel>(AdornedElement);
movePx = canvas.GridPxiel;

if (Math.Abs(tempX) >= movePx)
{
offsetX = Math.Round(tempX / movePx) * movePx;
tempX -= offsetX;
canvas.MoveControls(offsetX, 0);
}

if (Math.Abs(tempY) >= movePx)
{
offsetY = Math.Round(tempY / movePx) * movePx;
tempY -= offsetY;
canvas.MoveControls(0, offsetY);
}

}
else if (Mouse.MiddleButton == MouseButtonState.Pressed)
{
CaptureMouse();
var nowPoint = Mouse.GetPosition(CanvasPanel.GetParentObject<CanvasPanel>(AdornedElement));
int offsetX = (int)(nowPoint.X - lastPoint.X);
int offsetY = (int)(nowPoint.Y - lastPoint.Y);

CanvasPanel.GetParentObject<CanvasPanel>(AdornedElement).ZoomControls(offsetX, offsetY);
lastPoint = nowPoint;
}
}

private void SelectionAdorner_MouseDown(object sender, MouseButtonEventArgs e)
{
var canv = CanvasPanel.GetParentObject<CanvasPanel>(AdornedElement);
lastPoint = Mouse.GetPosition(canv);
Keyboard.Focus(canv);

//if (Keyboard.Modifiers == ModifierKeys.Control)
//{
// if (canv.SelectedItems.Contains(AdornedElement))
// {
// canv.SelectedItems.Remove(AdornedElement as FrameworkElement);
// canv.RefreshSelection();
// }
//}
}
}
}

+ 32
- 0
BeDesignerSCADA/Adorners/SelectionAlignLine.cs Переглянути файл

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace BeDesignerSCADA.Adorners
{
public class SelectionAlignLine : Adorner
{
public SelectionAlignLine(UIElement adornedElement, Point start, Point end) : base(adornedElement)
{
startPoint = start;
endPoint = end;
}

Point startPoint = default(Point);
Point endPoint = default(Point);
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
Rect adornerRect = new Rect(AdornedElement.DesiredSize);
Pen render = new Pen(new SolidColorBrush(Colors.RoyalBlue), 1);
render.DashCap = PenLineCap.Round;
render.DashStyle = new DashStyle(new List<double>() { 4, 2 }, 2);
drawingContext.DrawLine(render, startPoint, endPoint);
}
}
}

+ 9
- 0
BeDesignerSCADA/App.xaml Переглянути файл

@@ -0,0 +1,9 @@
<Application x:Class="BeDesignerSCADA.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BeDesignerSCADA"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

+ 17
- 0
BeDesignerSCADA/App.xaml.cs Переглянути файл

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace BeDesignerSCADA
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

+ 112
- 0
BeDesignerSCADA/BeDesignerSCADA.csproj Переглянути файл

@@ -0,0 +1,112 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<ApplicationIcon>Images\fyf.ico</ApplicationIcon>
</PropertyGroup>

<ItemGroup>
<Compile Remove="ArcGauge.cs" />
<Compile Remove="AssemblyInfo.cs" />
<Compile Remove="DigitalNumber.cs" />
<Compile Remove="GraphArrow.xaml.cs" />
<Compile Remove="GraphStar.xaml.cs" />
<Compile Remove="Helper\Config.cs" />
<Compile Remove="KnobButton.cs" />
<Compile Remove="NumberBox.cs" />
<Compile Remove="StatusLight.cs" />
<Compile Remove="SwitchButton.cs" />
<Compile Remove="TheButton.xaml.cs" />
<Compile Remove="TheCheckBox.xaml.cs" />
<Compile Remove="TheComboBox.xaml.cs" />
<Compile Remove="TheGroupBox.xaml.cs" />
<Compile Remove="TheImage.xaml.cs" />
<Compile Remove="TheRadioButton.cs" />
<Compile Remove="TheSlider.cs" />
<Compile Remove="TheTextBlock.xaml.cs" />
<Compile Remove="TheTextBox.cs" />
<Compile Remove="TheTimer.cs" />
<Compile Remove="TheToggleButton.xaml.cs" />
<Compile Remove="WaveProgressBar.cs" />
</ItemGroup>

<ItemGroup>
<None Remove="Fonts\ds-digib.ttf" />
<None Remove="Images\bj.png" />
<None Remove="Images\fyf.ico" />
<None Remove="Images\gaugeMask.png" />
<None Remove="Images\hbl.ico" />
<None Remove="Images\ico.ico" />
<None Remove="Images\redis.png" />
<None Remove="Images\State0.png" />
<None Remove="Images\State1.png" />
<None Remove="Images\State11.png" />
<None Remove="Images\State2.png" />
<None Remove="Images\timericon.png" />
<None Remove="Images\win.png" />
<None Remove="Images\wx.jpg" />
<None Remove="Images\zfb.jpg" />
<None Remove="Images\光柱.png" />
</ItemGroup>

<ItemGroup>
<Content Include="Images\fyf.ico" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="AvalonEdit" Version="6.1.3.50" />
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.4.0" />
<PackageReference Include="MahApps.Metro.IconPacks" Version="4.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.3.0" />
<PackageReference Include="Microsoft.Toolkit.Mvvm" Version="7.1.2" />
<PackageReference Include="MQTTnet" Version="3.1.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="StackExchange.Redis" Version="2.6.66" />
</ItemGroup>

<ItemGroup>
<Reference Include="Antlr3.Runtime">
<HintPath>DLL\Antlr3.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unvell.ReoScript">
<HintPath>DLL\Unvell.ReoScript.dll</HintPath>
</Reference>
</ItemGroup>

<ItemGroup>
<Resource Include="Fonts\ds-digib.ttf" />
<Resource Include="Images\bj.png" />
<Resource Include="Images\fyf.ico" />
<Resource Include="Images\gaugeMask.png" />
<Resource Include="Images\hbl.ico" />
<Resource Include="Images\ico.ico" />
<Resource Include="Images\redis.png" />
<Resource Include="Images\State0.png" />
<Resource Include="Images\State1.png" />
<Resource Include="Images\State11.png" />
<Resource Include="Images\State2.png" />
<Resource Include="Images\timericon.png" />
<Resource Include="Images\win.png" />
<Resource Include="Images\wx.jpg" />
<Resource Include="Images\zfb.jpg" />
<Resource Include="Images\光柱.png" />
</ItemGroup>

<ItemGroup>
<Folder Include="Helper\" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BPASmart.Model\BPASmart.Model.csproj" />
<ProjectReference Include="..\BPASmartClient.Compiler\BPASmartClient.Compiler.csproj" />
<ProjectReference Include="..\BPASmartClient.DATABUS\BPASmartClient.DATABUS.csproj" />
<ProjectReference Include="..\BPASmartClient.MessageCommunication\BPASmartClient.MessageCommunication.csproj" />
<ProjectReference Include="..\BPASmartClient.MessageName\BPASmartClient.MessageName.csproj" />
<ProjectReference Include="..\BPASmartClient.SCADAControl\BPASmartClient.SCADAControl.csproj" />
</ItemGroup>

</Project>

+ 31
- 0
BeDesignerSCADA/BeDesignerSCADA.sln Переглянути файл

@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32210.238
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeDesignerSCADA", "BeDesignerSCADA.csproj", "{B8AB1764-33B1-49C7-9C20-EC8E1292BD67}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICOTest", "..\ICOTest\ICOTest.csproj", "{3E9DDFC3-7CB2-47D9-BC91-AAFDC8425595}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B8AB1764-33B1-49C7-9C20-EC8E1292BD67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8AB1764-33B1-49C7-9C20-EC8E1292BD67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8AB1764-33B1-49C7-9C20-EC8E1292BD67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8AB1764-33B1-49C7-9C20-EC8E1292BD67}.Release|Any CPU.Build.0 = Release|Any CPU
{3E9DDFC3-7CB2-47D9-BC91-AAFDC8425595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E9DDFC3-7CB2-47D9-BC91-AAFDC8425595}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E9DDFC3-7CB2-47D9-BC91-AAFDC8425595}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E9DDFC3-7CB2-47D9-BC91-AAFDC8425595}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {768373E6-CC1A-4B37-95FC-9934B59C3D02}
EndGlobalSection
EndGlobal

+ 53
- 0
BeDesignerSCADA/Common/PropertyHelper.cs Переглянути файл

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace BeDesignerSCADA.Common
{
/// <summary>
/// 编辑脚本时获取控件属性
/// </summary>
public class PropertyHelper
{
public static string[] ableProperties = new string[]
{ "IsChecked", "Value", "CurValue", "StatusValue", "NumberValue", "Text",
"Direction","RefreshData","ChangedText","Content"
};
public static List<ControlName> GetCustomerControlProperty(List<FrameworkElement> selectItems)
{
List<ControlName> result = new List<ControlName>();
foreach (var control in selectItems)
{
var typeCtl = control.GetType();
if (typeCtl.GetProperties().Count(p => ableProperties.Contains(p.Name)) == 0)
continue;

var pare = new ControlName(control.Name, null);
result.Add(pare);
pare.Properties = typeCtl.GetProperties()
.Where(p => ableProperties.Contains(p.Name))
.Select(x => new ControlName(x.Name, pare)).ToList();
}

return result;
}
}

public class ControlName
{
public ControlName(string name, ControlName parent)
{
Name = name;
Parent = parent;
}

public ControlName Parent { get; set; }

public string Name { get; set; }

public IEnumerable<ControlName> Properties { get; set; }
}
}

+ 902
- 0
BeDesignerSCADA/Controls/CanvasPanel.cs Переглянути файл

@@ -0,0 +1,902 @@
using BeDesignerSCADA.Adorners;
using BeDesignerSCADA.Speical;
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using Microsoft.Toolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;

namespace BeDesignerSCADA.Controls
{
public class CanvasPanel : Canvas
{
public CanvasPanel()
{
UseLayoutRounding = true;
Drop += CanvasPanel_Drop;
CopySelectItemsCommand = new RelayCommand(CopySelectItems);
PasteSelectItemsCommand = new RelayCommand(PasteSelectItems);
DeleteSelectItemsCommand = new RelayCommand(DeleteSelectItems);
SetTopLayerCommand = new RelayCommand(SetTopLayer);
SetBottomLayerCommand = new RelayCommand(SetBottomLayer);
SelectedItems = new ObservableCollection<FrameworkElement>();
//ResourceDictionary resourceDictionary = new ResourceDictionary();
//Application.LoadComponent(resourceDictionary, new Uri("/BeDesignerSCADA;component/Themes/Styles.xaml", UriKind.Relative));
//ContextMenu = resourceDictionary.FindName("CanvasRightMenu") as ContextMenu;
ContextMenu=Application.Current.Resources["CanvasRightMenu"] as ContextMenu;
KeyDown += CanvasPanel_KeyDown;
}

#region 添加控件
private void CanvasPanel_Drop(object sender, DragEventArgs e)
{
Type type = e.Data.GetData("System.RuntimeType") as Type;
var t = type.GetCustomAttributes(typeof(ControlTypeAttribute), false);
if (t.Length > 0)
{
Console.WriteLine((t as ControlTypeAttribute[])[0].Group);
}

try
{
var control = Activator.CreateInstance(type) as FrameworkElement;
control.Name = GetControlName(type);
Children.Add(control);

var xPos = e.GetPosition(this).X;
var yPos = e.GetPosition(this).Y;
if (xPos % GridPxiel != 0)
xPos = (GridPxiel - xPos % GridPxiel) + xPos;
if (yPos % GridPxiel != 0)
yPos = (GridPxiel - yPos % GridPxiel) + yPos;

SetLeft(control, xPos);
SetTop(control, yPos);

SelectedItems = new ObservableCollection<FrameworkElement>() { control };
SelectedItem = control;
}
catch (Exception)
{
}

}

string GetControlName(Type ctrlType)
{
var children = Children.GetEnumerator();
children.Reset();
List<string> names = new List<string>();
while (children.MoveNext())
{
if (children.Current.GetType().Name == ctrlType.Name)
{
names.Add((children.Current as FrameworkElement).Name);
}
}

var nameIndex = names.Count;
while (names.Contains($"{ctrlType.Name.ToLower().Replace("the", string.Empty)}{nameIndex}"))
{
nameIndex++;
}

return $"{ctrlType.Name.ToLower().Replace("the", string.Empty)}{nameIndex}";
}
#endregion

#region 初始化
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
{
if (visualAdded is Border || visualRemoved is Border)
{
return;
}

if (visualAdded is FrameworkElement ctrl)
{
ctrl.PreviewMouseLeftButtonDown += Ctrl_MouseLeftButtonDown;
}
if (visualRemoved is FrameworkElement ctr)
{
ctr.PreviewMouseLeftButtonDown -= Ctrl_MouseLeftButtonDown;
}

base.OnVisualChildrenChanged(visualAdded, visualRemoved);
}
#endregion

#region 单击选中项处理
/// <summary>
/// 单击了控件时:不调用框选的刷新方式
/// </summary>
bool isClickedControl = false;
/// <summary>
/// 左键按下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Ctrl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (sender is FrameworkElement ctl)
{
var cp = GetParentObject<CanvasPanel>(ctl);
if (Keyboard.Modifiers == ModifierKeys.Control)
{
cp.SelectedItems.Add(ctl);
}
else
{
cp.SelectedItems = new ObservableCollection<FrameworkElement>() { ctl };
}
isClickedControl = true;
RefreshSelection();
}
}
/// <summary>
/// 获取属性
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static T GetParentObject<T>(DependencyObject obj) where T : FrameworkElement
{
DependencyObject parent = VisualTreeHelper.GetParent(obj);
while (parent != null)
{
if (parent is T)
{
return (T)parent;
}
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
#endregion

#region 右键菜单
#endregion

#region 绘制选择框
Border selectionBorder = new Border()
{
Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#557F7F7F")),
BorderThickness = new Thickness(1),
BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF303030")),
};

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
selectionStart = e.GetPosition(this);
if (!this.Children.Contains(selectionBorder))
{
this.Children.Add(selectionBorder);
this.CaptureMouse();
}

}

Point selectionStart = default;
protected override void OnMouseMove(MouseEventArgs e)
{
if (isClickedControl)
{
return;
}
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
var nowPoint = e.GetPosition(this);

var offsetX = nowPoint.X - selectionStart.X;
var offsetY = nowPoint.Y - selectionStart.Y;
Clear();

selectionBorder.Width = Math.Abs(offsetX);
selectionBorder.Height = Math.Abs(offsetY);
// 分四种情况绘制
if (offsetX >= 0 && offsetY >= 0)// 右下
{
SetLeft(selectionBorder, selectionStart.X);
SetTop(selectionBorder, selectionStart.Y);
}
else if (offsetX > 0 && offsetY < 0)// 右上
{
SetLeft(selectionBorder, selectionStart.X);
SetBottom(selectionBorder, ActualHeight - selectionStart.Y);

}
else if (offsetX < 0 && offsetY > 0)// 左下
{
SetRight(selectionBorder, ActualWidth - selectionStart.X);
SetTop(selectionBorder, selectionStart.Y);
}
else if (offsetX < 0 && offsetY < 0)// 左上
{
SetRight(selectionBorder, ActualWidth - selectionStart.X);
SetBottom(selectionBorder, ActualHeight - selectionStart.Y);
}


}
}

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (double.IsNaN(GetLeft(selectionBorder)))
{
SetLeft(selectionBorder, ActualWidth - GetRight(selectionBorder) - selectionBorder.ActualWidth);
}
if (double.IsNaN(GetTop(selectionBorder)))
{
SetTop(selectionBorder, ActualHeight - GetBottom(selectionBorder) - selectionBorder.ActualHeight);
}

FrameSelection(GetLeft(selectionBorder), GetTop(selectionBorder), selectionBorder.Width, selectionBorder.Height);
selectionBorder.Width = 0;
selectionBorder.Height = 0;
this.Children.Remove(selectionBorder);
this.ReleaseMouseCapture();
}

private void Clear()
{
SetLeft(selectionBorder, double.NaN);
SetRight(selectionBorder, double.NaN);
SetTop(selectionBorder, double.NaN);
SetBottom(selectionBorder, double.NaN);
}

#endregion

#region 选中属性
public FrameworkElement SelectedItem
{
get { return (FrameworkElement)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(FrameworkElement), typeof(CanvasPanel), new PropertyMetadata(null, OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as CanvasPanel)?.RefreshSelection1();
public void RefreshSelection1()
{
}
#endregion

#region 框选
public ObservableCollection<FrameworkElement> SelectedItems
{
get { return (ObservableCollection<FrameworkElement>)GetValue(SelectedItemsProperty); }
set { SetValue(SelectedItemsProperty, value); }
}
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(ObservableCollection<FrameworkElement>), typeof(CanvasPanel), new PropertyMetadata(null, OnSelectedItemsChanged));

private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as CanvasPanel)?.RefreshSelection();

public void RefreshSelection()
{
foreach (var item in Children)
{
if (!(item is IExecutable))
continue;

var ele = item as FrameworkElement;
if (ele == null) continue;

var layer = AdornerLayer.GetAdornerLayer(ele);
var arr = layer.GetAdorners(ele);//获取该控件上所有装饰器,返回一个数组
if (arr != null)
{
for (int i = arr.Length - 1; i >= 0; i--)
{
layer.Remove(arr[i]);
}
}
}

if (SelectedItems != null)
{
foreach (var item in SelectedItems)
{
var layer = AdornerLayer.GetAdornerLayer(item);
layer.Add(new SelectionAdorner(item));
SelectedItem = item;
}
}
}

/// <summary>
/// 移除所有选择装饰器
/// </summary>
public void ClearSelection()
{
foreach (var item in Children)
{
if (!(item is IExecutable))
continue;

var ele = item as FrameworkElement;
if (ele == null) continue;

var layer = AdornerLayer.GetAdornerLayer(ele);
var arr = layer.GetAdorners(ele);//获取该控件上所有装饰器,返回一个数组
if (arr != null)
{
for (int i = arr.Length - 1; i >= 0; i--)
{
layer.Remove(arr[i]);
}
}
}
}

/// <summary>
/// 计算框选项
/// </summary>
private void FrameSelection(double x, double y, double width, double height)
{
if (width > 0 || height > 0)
{
isClickedControl = false;
}
if (isClickedControl)
{
isClickedControl = false;
SelectedItems = new ObservableCollection<FrameworkElement>();
return;
}
SelectedItems = new ObservableCollection<FrameworkElement>();
foreach (var item in Children)
{
if (item is FrameworkElement ctrl && !(ctrl is Border))
{
// 框左上角
var left = GetLeft(ctrl);
var top = GetTop(ctrl);
if (left >= x && left <= x + width && top >= y && top <= y + height)
{
if (!SelectedItems.Contains(ctrl))
SelectedItems.Add(ctrl);
}

// 框右下角
var right = left + ctrl.ActualWidth;
var bottom = top + ctrl.ActualHeight;
if (right >= x && right <= x + width && bottom >= y && bottom <= y + height)
{
if (!SelectedItems.Contains(ctrl))
SelectedItems.Add(ctrl);
}

// 框右上角
if (right >= x && right <= x + width && top >= y && top <= y + height)
{
if (!SelectedItems.Contains(ctrl))
SelectedItems.Add(ctrl);
}

// 框左下角
if (left >= x && left <= x + width && bottom >= y && bottom <= y + height)
{
if (!SelectedItems.Contains(ctrl))
SelectedItems.Add(ctrl);
}
}
}

RefreshSelection();
}
#endregion

#region 外部调用
public List<FrameworkElement> GetAllExecChildren()
{
List<FrameworkElement> result = new List<FrameworkElement>();
foreach (var ctrl in Children)
{
if (ctrl is IExecutable exec)
{
result.Add(ctrl as FrameworkElement);
}
}

return result;
}

/// <summary>
/// 对齐像素单位
/// </summary>
public int GridPxiel
{
get { return (int)GetValue(GridPxielProperty); }
set { SetValue(GridPxielProperty, value); }
}
public static readonly DependencyProperty GridPxielProperty =
DependencyProperty.Register("GridPxiel", typeof(int), typeof(CanvasPanel), new PropertyMetadata(4));


public void MoveControls(double offsetX, double offsetY)
{
ClearAlignLine();

// 获取可对齐的点
List<Point> points = new List<Point>();
foreach (FrameworkElement ctrl in Children)
{
if (!SelectedItems.Contains(ctrl))
{
// 左上的点
Point item = new Point(GetLeft(ctrl), GetTop(ctrl));
points.Add(item);

// 左下的点
Point itemlb = new Point(GetLeft(ctrl), GetTop(ctrl) + ctrl.ActualHeight);
points.Add(itemlb);

// 右下的点
Point itemrb = new Point(GetLeft(ctrl) + ctrl.ActualWidth, GetTop(ctrl) + ctrl.ActualHeight);
points.Add(itemrb);

// 右上的点
Point itemrt = new Point(GetLeft(ctrl) + ctrl.ActualWidth, GetTop(ctrl));
points.Add(itemrt);
}
}

// 控件移动
foreach (var item in SelectedItems)
{
var moveX = GetLeft(item) + offsetX;
moveX = (moveX < 0) ? 0 : moveX;

var moveY = GetTop(item) + offsetY;
moveY = moveY < 0 ? 0 : moveY;

if (moveX % GridPxiel != 0)
moveX = (GridPxiel - moveX % GridPxiel) + moveX;
if (moveY % GridPxiel != 0)
moveY = (GridPxiel - moveY % GridPxiel) + moveY;

SetLeft(item, moveX);
SetTop(item, moveY);
}

// 计算是否显示对齐线
var targetItemTop = SelectedItems?.Min(x => GetTop(x));
var targetItem = SelectedItems.FirstOrDefault(x => GetTop(x) == targetItemTop);
var lefAlign = points.FirstOrDefault(x => Math.Abs(x.X - GetLeft(targetItem)) == 0);
if (lefAlign != default)
{
//SetLeft(targetItem, lefAlign.X);
var layer = AdornerLayer.GetAdornerLayer(this);
layer.Add(new SelectionAlignLine(this, lefAlign, new Point(GetLeft(targetItem), GetTop(targetItem))));
}

var topAlign = points.FirstOrDefault(x => Math.Abs(x.Y - GetTop(targetItem)) == 0);
if (topAlign != default)
{
//SetTop(targetItem, topAlign.Y);
var layer = AdornerLayer.GetAdornerLayer(this);
layer.Add(new SelectionAlignLine(this, topAlign, new Point(GetLeft(targetItem), GetTop(targetItem))));
}

int px = 20;
// 网格对齐
if (UseAutoAlignment)
{
foreach (var item in SelectedItems)
{
var left = GetLeft(item);
if (left % px <= 1)
{
SetLeft(item, (int)left / px * px);
}

var top = GetTop(item);
if (top % px <= 1)
{
SetTop(item, (int)top / px * px);
}
}
}
}

/// <summary>
/// 清除绘制的对齐线
/// </summary>
public void ClearAlignLine()
{
var arr = AdornerLayer.GetAdornerLayer(this).GetAdorners(this);
if (arr != null)
{
for (int i = arr.Length - 1; i >= 0; i--)
{
AdornerLayer.GetAdornerLayer(this).Remove(arr[i]);
}
}
}

public void ZoomControls(int offsetX, int offsetY)
{
foreach (var item in SelectedItems)
{
if (item.ActualHeight + offsetY > 10)
{
item.Height += offsetY;
}
if (item.ActualWidth + offsetX > 10)
{
item.Width += offsetX;
}
}
}
#endregion

#region 对齐操作
/// <summary>
/// 是否使用网格对齐 10px
/// </summary>
public bool UseAutoAlignment
{
get { return (bool)GetValue(UseAutoAlignmentProperty); }
set { SetValue(UseAutoAlignmentProperty, value); }
}
public static readonly DependencyProperty UseAutoAlignmentProperty =
DependencyProperty.Register("UseAutoAlignment", typeof(bool), typeof(CanvasPanel), new PropertyMetadata(false));


public void AlignLeft()
{
if (SelectedItems == null || SelectedItems.Count == 0)
return;

var leftMin = SelectedItems.Min(x => Canvas.GetLeft(x));
foreach (var item in SelectedItems)
{
SetLeft(item, leftMin);
}
}

public void AlignRight()
{
if (SelectedItems == null || SelectedItems.Count == 0)
return;

var rightMax = SelectedItems.Max(x => GetLeft(x) + x.ActualWidth);
foreach (var item in SelectedItems)
{
var targetLeft = rightMax - item.ActualWidth;
SetLeft(item, targetLeft);
}
}

public void AlignCenter()
{
if (SelectedItems == null || SelectedItems.Count == 0)
return;

var leftmin = SelectedItems.Min(x => GetLeft(x));
var rightmax = SelectedItems.Max(x => GetLeft(x) + x.ActualWidth);
var center = (rightmax - leftmin) / 2 + leftmin;

foreach (var item in SelectedItems)
{
var target = center - (item.ActualWidth / 2);
SetLeft(item, target);
}
}

public void AlignTop()
{
if (SelectedItems == null || SelectedItems.Count == 0)
return;

var topMin = SelectedItems.Min(x => GetTop(x));
foreach (var item in SelectedItems)
{
SetTop(item, topMin);
}
}

public void AlignBottom()
{
if (SelectedItems == null || SelectedItems.Count == 0)
return;

var botMax = SelectedItems.Max(x => GetTop(x) + x.ActualHeight);
foreach (var item in SelectedItems)
{
var targetLeft = botMax - item.ActualHeight;
SetTop(item, targetLeft);
}
}

public void VertialLayout()
{
if (SelectedItems == null || SelectedItems.Count < 3)
return;

var topCtl = SelectedItems.Min(x => GetTop(x) + x.ActualHeight);
var botCtrl = SelectedItems.Max(x => GetTop(x));
var emptyHeight = botCtrl - topCtl;

var orderCtrl = SelectedItems.OrderBy(x => GetTop(x)).ToList();
orderCtrl.RemoveAt(0);
orderCtrl.RemoveAt(orderCtrl.Count - 1);
var useSpace = orderCtrl.Sum(x => x.ActualHeight);

var ableSpaceAvg = (emptyHeight - useSpace) / (SelectedItems.Count - 1);
double nowPostion = topCtl;
foreach (var item in orderCtrl)
{
SetTop(item, nowPostion + ableSpaceAvg);
nowPostion += item.ActualHeight + ableSpaceAvg;
}
}

public void HorizontalLayout()
{
if (SelectedItems == null || SelectedItems.Count < 3)
return;

var leftCtl = SelectedItems.Min(x => GetLeft(x) + x.ActualWidth);
var rightCtrl = SelectedItems.Max(x => GetLeft(x));
var emptyHeight = rightCtrl - leftCtl;

var orderCtrl = SelectedItems.OrderBy(x => GetLeft(x)).ToList();
orderCtrl.RemoveAt(0);
orderCtrl.RemoveAt(orderCtrl.Count - 1);
var useSpace = orderCtrl.Sum(x => x.ActualWidth);

var ableSpaceAvg = (emptyHeight - useSpace) / (SelectedItems.Count - 1);
double nowPostion = leftCtl;
foreach (var item in orderCtrl)
{
SetLeft(item, nowPostion + ableSpaceAvg);
nowPostion += item.ActualWidth + ableSpaceAvg;
}
}
#endregion

#region 按键操作
public RelayCommand CopySelectItemsCommand { get; set; }
public RelayCommand PasteSelectItemsCommand { get; set; }
public RelayCommand DeleteSelectItemsCommand { get; set; }
public RelayCommand SetTopLayerCommand { get; set; }
public RelayCommand SetBottomLayerCommand { get; set; }

List<FrameworkElement> copyTemp = new List<FrameworkElement>();

private void CanvasPanel_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.C && Keyboard.Modifiers == ModifierKeys.Control)
{
CopySelectItems();
}
else if (e.Key == Key.V && Keyboard.Modifiers == ModifierKeys.Control)
{
PasteSelectItems();
}
else if (e.Key == Key.Delete)
{
DeleteSelectItems();
}
else if (e.Key == Key.Up)
{
var offset = -1;
foreach (var item in SelectedItems)
{
SetTop(item, (GetTop(item) + offset) < 0 ? 0 : GetTop(item) + offset);
}
e.Handled = true;
}
else if (e.Key == Key.Down)
{
var offset = 1;
foreach (var item in SelectedItems)
{
SetTop(item, (GetTop(item) + offset) < 0 ? 0 : GetTop(item) + offset);
}
e.Handled = true;
}
else if (e.Key == Key.Left)
{
var offset = -1;
foreach (var item in SelectedItems)
{
SetLeft(item, (GetLeft(item) + offset) < 0 ? 0 : GetLeft(item) + offset);
}
e.Handled = true;

}
else if (e.Key == Key.Right)
{
var offset = 1;
foreach (var item in SelectedItems)
{
SetLeft(item, (GetLeft(item) + offset) < 0 ? 0 : GetLeft(item) + offset);
}
e.Handled = true;
}
}

/// <summary>
/// 复制
/// </summary>
public void CopySelectItems()
{
copyTemp.Clear();
foreach (var item in SelectedItems)
{
copyTemp.Add(item);
}
}

/// <summary>
/// 粘贴
/// </summary>
public void PasteSelectItems()
{
SelectedItems.Clear();
foreach (var item in copyTemp)
{
var xml = XamlWriter.Save(item);
var element = XamlReader.Parse(xml) as FrameworkElement;
element.Name += "_1";

SetLeft(element, GetLeft(element) + 10);
SetTop(element, GetTop(element) + 10);

Children.Add(element);
SelectedItems.Add(element);
}

// 将复制的内容替换 以便处理连续复制
copyTemp.Clear();
foreach (var item in SelectedItems)
{
copyTemp.Add(item);
}
RefreshSelection();
}

/// <summary>
/// 置于顶层
/// </summary>
public void SetTopLayer()
{
if (SelectedItems.Count == 0)
return;

foreach (var item in SelectedItems)
{
Children.Remove(item);
}

foreach (var item in SelectedItems)
{
Children.Add(item);
}
}

/// <summary>
/// 置于底层
/// </summary>
public void SetBottomLayer()
{
if (SelectedItems.Count == 0)
return;

foreach (var item in SelectedItems)
{
Children.Remove(item);
}

foreach (var item in SelectedItems)
{
Children.Insert(0, item);
}
}
/// <summary>
/// 删除
/// </summary>
public void DeleteSelectItems()
{
foreach (var item in SelectedItems)
{
Children.Remove(item);
}

SelectedItems.Clear();
RefreshSelection();
}
#endregion

#region 运行Xaml 保存 读取
public List<FrameworkElement> Generator()
{
List<FrameworkElement> elements = new List<FrameworkElement>();
foreach (var item in Children)
{
// 排除非自定义的控件们
if (!(item is IExecutable))
continue;

var xml = XamlWriter.Save(item);
var ele = XamlReader.Parse(xml) as FrameworkElement;
elements.Add(ele);
}

return elements;
}

/// <summary>
/// 保存数据到文本
/// </summary>
public string Save()
{
StringBuilder sb = new StringBuilder();

foreach (var item in Children)
{

var xml = XamlWriter.Save(item);
sb.Append(xml + "\r\n");
}

return sb.ToString();
}

/// <summary>
/// 读取文件
/// </summary>
public void Load(string path)
{
Children.Clear();
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (StreamReader sr = new StreamReader(fs, System.Text.Encoding.Unicode))
{
while (sr.Peek() > -1)
{
string str = sr.ReadLine();
//if (!str.Contains("NewConveyorBelt"))
{
try
{
var ele = XamlReader.Parse(str) as FrameworkElement;
Children.Add(ele);
}
catch (Exception ex)
{

}
}
}
}

SelectedItems?.Clear();
}
#endregion
}
}

+ 32
- 0
BeDesignerSCADA/Controls/RunCanvas.xaml Переглянути файл

@@ -0,0 +1,32 @@
<UserControl x:Class="BeDesignerSCADA.Controls.RunCanvas"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.Controls"
xmlns:con="clr-namespace:BeDesignerSCADA.Converters"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<con:ZoomConverter x:Key="ZoomX" IsHeight="False"/>
<con:ZoomConverter x:Key="ZoomY" IsHeight="True"/>
</UserControl.Resources>
<Grid ClipToBounds="True">
<Canvas x:Name="RootCanvas" ClipToBounds="True" Background="Transparent" MouseLeftButtonUp="RootCanvas_MouseLeftButtonUp"
MouseMove="RootCanvas_MouseMove" MouseLeftButtonDown="RootCanvas_MouseLeftButtoDown" MouseWheel="RootCanvas_MouseWheel">
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="Scale"/>
<TranslateTransform x:Name="Translate"/>
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>

<Grid VerticalAlignment="Bottom" Background="#4B959595">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="8 0">
<CheckBox x:Name="DragEnable" Content="拖动" Margin="4"/>
<CheckBox x:Name="ZoomEnable" Content="缩放" Margin="4"/>
</StackPanel>
</Grid>
</Grid>
</UserControl>

+ 133
- 0
BeDesignerSCADA/Controls/RunCanvas.xaml.cs Переглянути файл

@@ -0,0 +1,133 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.Controls
{
/// <summary>
/// RunCanvas.xaml 的交互逻辑
/// </summary>
public partial class RunCanvas : UserControl
{
public RunCanvas()
{
InitializeComponent();
Unloaded += (s, e) => Destory();
}

/// <summary>
/// Dispose子集
/// </summary>
public void Destory()
{
foreach (var item in RootCanvas.Children)
{
if (item is IDisposable disposable)
{
disposable.Dispose();
}
}
}

public void Run(List<FrameworkElement> canvas)
{
RootCanvas.Children.Clear();
foreach (FrameworkElement element in canvas)
{
//if (element.GetType().GetInterface("IExecutable")!=null)
//{
// element.GetType().GetProperty("IsExecuteState").SetValue(element, true);
//}

if (element is IExecutable executable)
executable.IsExecuteState = true;

RootCanvas.Children.Add(element);
RegisterJsName(element);
}
}

// 注册名称到Js
static void RegisterJsName(FrameworkElement element)
{
Config.GetInstance().SetVariable(element.Name, element);
if (element is Panel panel)
{
foreach (var item in panel.Children)
{
RegisterJsName(item as FrameworkElement);
}
}
}

#region 拖动与缩放
private void RootCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (DragEnable.IsChecked == false)
{
return;
}

if (e.LeftButton == MouseButtonState.Pressed && isPressed)
{
Point point = e.GetPosition(this);
var movex = (point.X - last.X);
var movey = (point.Y - last.Y);

Translate.X += movex;
Translate.Y += movey;
last = point;

}
}

bool isPressed = false;
Point last;//记录上次鼠标坐标位置
private void RootCanvas_MouseLeftButtoDown(object sender, MouseButtonEventArgs e)
{
last = e.GetPosition(this);
isPressed = true;
}

private void RootCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
isPressed = false;
}

// 缩放
private void RootCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (ZoomEnable.IsChecked == false)
{
return;
}
var zoomS = (e.Delta / 960d);
var zoom = zoomS + Scale.ScaleX;
if (zoom > 3 || zoom < 0.8)
{
return;
}
Scale.ScaleX = Scale.ScaleY = zoom;

Point mouse = e.GetPosition(RootCanvas);
Point newMouse = new Point(mouse.X * zoomS, mouse.Y * zoomS);

Translate.X -= newMouse.X;
Translate.Y -= newMouse.Y;
}
#endregion
}
}

+ 36
- 0
BeDesignerSCADA/Converters/BoolToVisibilityConverter.cs Переглянути файл

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace BeDesignerSCADA.Converters
{
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolToVisibilityConverter : IValueConverter
{
static BoolToVisibilityConverter()
{
Instance = new BoolToVisibilityConverter();
}

public static BoolToVisibilityConverter Instance
{
get;
private set;
}

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? Visibility.Visible : Visibility.Collapsed;
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

+ 28
- 0
BeDesignerSCADA/Converters/HalfNumberConverter.cs Переглянути файл

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace BeDesignerSCADA.Converters
{
public class HalfNumberConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (double.TryParse(value.ToString(), out double val))
{
return val / 2;
}

return 0;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}

+ 31
- 0
BeDesignerSCADA/Converters/ZoomConverter.cs Переглянути файл

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace BeDesignerSCADA.Converters
{
public class ZoomConverter : IValueConverter
{
public bool IsHeight { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (double.TryParse(value.ToString(), out double zoom))
{
return IsHeight ? zoom * 1080 : zoom * 1920;
}
else
{
return IsHeight ? 1080 : 1920;
}
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
}

+ 198
- 0
BeDesignerSCADA/CustomerControls/ArcGauge.cs Переглянути файл

@@ -0,0 +1,198 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
public class ArcGauge : Control, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public ArcGauge()
{
Width = 300;
Height = 300;
SetCurrentValue(ValueProperty, 0d);
SetCurrentValue(MinValueProperty, 0d);
SetCurrentValue(MaxValueProperty, 100d);
}

private void InitTick()
{
// 画大刻度
for (int i = 0; i < 11; i++)
{
Line line = new Line();
line.X1 = 0;
line.Y1 = 0;
line.X2 = 0;
line.Y2 = 12;
line.Stroke = Brushes.White;
line.StrokeThickness = 2;
line.HorizontalAlignment = HorizontalAlignment.Center;
line.RenderTransformOrigin = new Point(0.5, 0.5);
line.RenderTransform = new RotateTransform() { Angle = -140 + i * 28 };
bdGrid.Children.Add(line);
DrawText();
}

// 画小刻度
for (int i = 0; i < 10; i++)
{
var start = -140 + 28 * i + 2.8;
for (int j = 0; j < 9; j++)
{
Line line = new Line();
line.X1 = 0;
line.Y1 = 0;
line.X2 = 0;
line.Y2 = 6;
line.Stroke = Brushes.White;
line.StrokeThickness = 1;
line.HorizontalAlignment = HorizontalAlignment.Center;
line.RenderTransformOrigin = new Point(0.5, 0.5);
line.RenderTransform = new RotateTransform() { Angle = start + j * 2.8 };
bdGrid.Children.Add(line);
}
}
}

List<TextBlock> textLabels = new List<TextBlock>();
private void DrawText()
{
foreach (var item in textLabels)
{
bdGrid.Children.Remove(item);
}
textLabels.Clear();

var per = MaxValue / 10;
for (int i = 0; i < 11; i++)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = $"{MinValue + (per * i)}";
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.RenderTransformOrigin = new Point(0.5, 0.5);
textBlock.RenderTransform = new RotateTransform() { Angle = -140 + i * 28 };
textBlock.Margin = new Thickness(12);
textBlock.Foreground = Brushes.White;
bdGrid.Children.Add(textBlock);
textLabels.Add(textBlock);
}
}

static ArcGauge()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ArcGauge), new FrameworkPropertyMetadata(typeof(ArcGauge)));
}

RotateTransform rotateTransform;
Grid bdGrid;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
rotateTransform = GetTemplateChild("PointRotate") as RotateTransform;
bdGrid = GetTemplateChild("bdGrid") as Grid;
Refresh();
InitTick();
}

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

[Category("值设定")]
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));

private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as ArcGauge)?.Refresh();

[Category("值设定")]
public double MinValue
{
get { return (double)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));

[Category("值设定")]
public double MaxValue
{
get { return (double)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}

public string ControlType => "控件";

public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));


private void Refresh()
{
if (rotateTransform == null)
return;
DrawText();
DoubleAnimation da = new DoubleAnimation();
da.Duration = new Duration(TimeSpan.FromMilliseconds(350));
da.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };

if (Value > MaxValue)
{
rotateTransform.Angle = 140;
da.To = 140;
}
else if (Value < MinValue)
{
rotateTransform.Angle = -140;
da.To = -140;
}
else
{
var range = MaxValue - MinValue;
var process = Value / range;
var tAngle = process * 280 - 140;
rotateTransform.Angle = tAngle;
da.To = tAngle;
}

rotateTransform.BeginAnimation(RotateTransform.AngleProperty, da);
}

public void Register()
{
Refresh();
}
}
}

+ 62
- 0
BeDesignerSCADA/CustomerControls/DigitalNumber.cs Переглянути файл

@@ -0,0 +1,62 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace BeDesignerSCADA.CustomerControls
{
public class DigitalNumber : Control, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public DigitalNumber()
{
Width = 80;
Height = 30;
}
public string ControlType => "控件";

static DigitalNumber()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DigitalNumber), new FrameworkPropertyMetadata(typeof(DigitalNumber)));
}

TextBlock text = null;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
text = GetTemplateChild("line") as TextBlock;
}

public double NumberValue
{
get { return (double)GetValue(NumberValueProperty); }
set { SetValue(NumberValueProperty, value); }
}
public static readonly DependencyProperty NumberValueProperty =
DependencyProperty.Register("NumberValue", typeof(double), typeof(DigitalNumber), new UIPropertyMetadata(0.00d));

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

public void Register()
{
}
}
}

+ 14
- 0
BeDesignerSCADA/CustomerControls/GraphArrow.xaml Переглянути файл

@@ -0,0 +1,14 @@
<UserControl x:Class="BeDesignerSCADA.CustomerControls.GraphArrow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
x:Name="root"
d:DesignHeight="44" d:DesignWidth="60" Foreground="#22DCF7">
<Grid>
<Path Data="M571.5,161.75L629,161.75 629,147.5 657.5,176 629,204.5 629,190.25 571.5,190.25z"
Stretch="Fill" Fill="{Binding ElementName=root,Path=Foreground}"/>
</Grid>
</UserControl>

+ 56
- 0
BeDesignerSCADA/CustomerControls/GraphArrow.xaml.cs Переглянути файл

@@ -0,0 +1,56 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// GraphArrow.xaml 的交互逻辑
/// </summary>
public partial class GraphArrow : UserControl, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public GraphArrow()
{
InitializeComponent();
Width = 80;
Height = 80;
}

public string ControlType => "图形";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
IsEnabled = true;
Register();
Style = null;
}
}
}

public void Register()
{
}
}
}

+ 14
- 0
BeDesignerSCADA/CustomerControls/GraphStar.xaml Переглянути файл

@@ -0,0 +1,14 @@
<UserControl x:Class="BeDesignerSCADA.CustomerControls.GraphStar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
x:Name="root"
d:DesignHeight="1056" d:DesignWidth="1094" Foreground="#78C94F">
<Grid>
<Path Data="M132.5,205.601L206.22,205.602 229,131.5 251.78,205.602 325.5,205.601 265.859,251.398 288.64,325.5 229,279.702 169.36,325.5 192.141,251.398z"
Fill="{Binding ElementName=root,Path=Foreground}" Stretch="Fill"/>
</Grid>
</UserControl>

+ 56
- 0
BeDesignerSCADA/CustomerControls/GraphStar.xaml.cs Переглянути файл

@@ -0,0 +1,56 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// GraphStar.xaml 的交互逻辑
/// </summary>
public partial class GraphStar : UserControl, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public GraphStar()
{
InitializeComponent();
Width = 100;
Height = 100;
}

public string ControlType => "图形";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
IsEnabled = true;
Register();
Style = null;
}
}
}

public void Register()
{
}
}
}

+ 240
- 0
BeDesignerSCADA/CustomerControls/KnobButton.cs Переглянути файл

@@ -0,0 +1,240 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
public class KnobButton : Slider, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

static KnobButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(KnobButton), new FrameworkPropertyMetadata(typeof(KnobButton)));
}

public KnobButton()
{
SetCurrentValue(WidthProperty, 150d);
SetCurrentValue(HeightProperty, 150d);
SetCurrentValue(MaximumProperty, 100d);
MouseDown += Path_MouseDown;
MouseMove += Path_MouseMove;
MouseWheel += Path_MouseWheel;
MouseLeftButtonUp += KnobButton_MouseLeftButtonUp;
Update();
}

#region 设计需要
public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
Register();
}
}

/// <summary>
/// 注册需要处理的事件
/// </summary>
public void Register()
{
ValueChanged += KnobButton_ValueChanged; ;
}

private void KnobButton_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Config.GetInstance().RunJsScipt(ValueChangedExecute);
}
#endregion

#region 绘制
private void InitTick()
{
// 画大刻度
for (int i = 0; i < 11; i++)
{
Line line = new Line();
line.X1 = 0;
line.Y1 = 0;
line.X2 = 0;
line.Y2 = 12;
line.Stroke = Brushes.Gray;
line.StrokeThickness = 2;
line.HorizontalAlignment = HorizontalAlignment.Center;
line.RenderTransformOrigin = new Point(0.5, 0.5);
line.RenderTransform = new RotateTransform() { Angle = -140 + i * 28 };
bdGrid.Children.Add(line);
}

// 画小刻度
for (int i = 0; i < 10; i++)
{
var start = -140 + 28 * i + 2.8;
for (int j = 0; j < 9; j++)
{
Line line = new Line();
line.X1 = 0;
line.Y1 = 0;
line.X2 = 0;
line.Y2 = 6;
line.Stroke = Brushes.Gray;
line.StrokeThickness = 1;
line.HorizontalAlignment = HorizontalAlignment.Center;
line.RenderTransformOrigin = new Point(0.5, 0.5);
line.RenderTransform = new RotateTransform() { Angle = start + j * 2.8 };
bdGrid.Children.Add(line);
}
}
}
#endregion
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
Update();
}

protected override void OnMaximumChanged(double oldMaximum, double newMaximum)
{
base.OnMaximumChanged(oldMaximum, newMaximum);
Update();
}

protected override void OnMinimumChanged(double oldMinimum, double newMinimum)
{
base.OnMinimumChanged(oldMinimum, newMinimum);
Update();
}

public string ValueChangedExecute
{
get { return (string)GetValue(ValueChangedExecuteProperty); }
set { SetValue(ValueChangedExecuteProperty, value); }
}
public static readonly DependencyProperty ValueChangedExecuteProperty =
DependencyProperty.Register("ValueChangedExecute", typeof(string), typeof(KnobButton), new PropertyMetadata(string.Empty));

public int Step
{
get { return (int)GetValue(StepProperty); }
set { SetValue(StepProperty, value); }
}
public static readonly DependencyProperty StepProperty =
DependencyProperty.Register("Step", typeof(int), typeof(KnobButton), new PropertyMetadata(1));

RotateTransform rotatevalue;
Grid bdGrid;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
rotatevalue = GetTemplateChild("rotatevalue") as RotateTransform;
bdGrid = GetTemplateChild("bdGrid") as Grid;
Update();
InitTick();
}

private void Update()
{
if (rotatevalue == null) return;
double perangle = 280 / (Maximum - Minimum);
double angle = (perangle * (Value - Minimum)) + 40;

DoubleAnimation da = new DoubleAnimation();
da.Duration = new Duration(TimeSpan.FromMilliseconds(350));
da.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
da.To = angle;

rotatevalue.Angle = angle;
rotatevalue.BeginAnimation(RotateTransform.AngleProperty, da);
}

Point lastpoint;
private void Path_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released) return;

CaptureMouse();
Point point = e.GetPosition(this);
double xmove = point.X - lastpoint.X;
double ymove = point.Y - lastpoint.Y;

double changeValue = (xmove + ymove) / 10 * Step;
if ((changeValue + Value) > Maximum)
{
if (Value < Maximum)
{
Value = Maximum;
}
return;
}

if ((changeValue + Value) < Minimum)
{
if (Value > Minimum)
{
Value = Minimum;
}
return;
}

Value = changeValue + Value;
lastpoint = point;
}

private void Path_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released) return;
lastpoint = e.GetPosition(this);
}

private void KnobButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ReleaseMouseCapture();
}

private void Path_MouseWheel(object sender, MouseWheelEventArgs e)
{
double changeValue = (e.Delta / 120) * Step;
if ((changeValue + Value) > Maximum)
{
if (Value < Maximum)
{
Value = Maximum;
}
return;
}

if ((changeValue + Value) < Minimum)
{
if (Value > Minimum)
{
Value = Minimum;
}
return;
}

Value = Value + changeValue;
Update();
}
}
}

+ 372
- 0
BeDesignerSCADA/CustomerControls/NumberBox.cs Переглянути файл

@@ -0,0 +1,372 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
public class NumberBox : TextBox, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

static NumberBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumberBox), new FrameworkPropertyMetadata(typeof(NumberBox)));

FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(CURVALUE, new PropertyChangedCallback(OnCurValueChanged));
CurValueProperty = DependencyProperty.Register("CurValue", typeof(double), typeof(NumberBox), metadata);

metadata = new FrameworkPropertyMetadata(MINVALUE, new PropertyChangedCallback(OnMinValueChanged));
MinValueProperty = DependencyProperty.Register("MinValue", typeof(double), typeof(NumberBox), metadata);

metadata = new FrameworkPropertyMetadata(MAXVALUE, new PropertyChangedCallback(OnMaxValueChanged));
MaxValueProperty = DependencyProperty.Register("MaxValue", typeof(double), typeof(NumberBox), metadata);

metadata = new FrameworkPropertyMetadata(DIGITS, new PropertyChangedCallback(OnDigitsChanged));
DigitsProperty = DependencyProperty.Register("Digits", typeof(int), typeof(NumberBox), metadata);
}
public string ControlType => "控件";

public NumberBox()
{
Width = 80;
Height = 30;
CurValue = 0.01;
Digits = 2;

VerticalContentAlignment = VerticalAlignment.Center;
Style = Application.Current.Resources["DesignNumberBox"] as Style;//FindResource("DesignNumberBox") as Style;

this.TextChanged += NumberBox_TextChanged;
this.PreviewKeyDown += NumberBox_KeyDown;
this.LostFocus += NumberBox_LostFocus;
DataObject.AddPastingHandler(this, NumberBox_Pasting);
Focusable = false;
}

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
IsEnabled = true;
Register();
Style = null;
Focusable = true;
}
}
}

public void Register()
{
}

#region DependencyProperty
private const double CURVALUE = 0; //当前值
private const double MINVALUE = double.MinValue; //最小值
private const double MAXVALUE = double.MaxValue; //最大值
private const int DIGITS = 15; //小数点精度

public static readonly DependencyProperty CurValueProperty;
public static readonly DependencyProperty MinValueProperty;
public static readonly DependencyProperty MaxValueProperty;
public static readonly DependencyProperty DigitsProperty;

public double CurValue
{
get
{
return (double)GetValue(CurValueProperty);
}
set
{
double v = value;
if (value < MinValue)
{
v = MinValue;
}
else if (value > MaxValue)
{
v = MaxValue;
}
v = Math.Round(v, Digits);

SetValue(CurValueProperty, v);
// if do not go into OnCurValueChanged then force update ui
if (v != value)
{
this.Text = v.ToString();
}
}
}
public double MinValue
{
get
{
return (double)GetValue(MinValueProperty);
}
set
{
SetValue(MinValueProperty, value);
}
}
public double MaxValue
{
get
{
return (double)GetValue(MaxValueProperty);
}
set
{
SetValue(MaxValueProperty, value);
}
}
public int Digits
{
get
{
return (int)GetValue(DigitsProperty);
}
set
{
int digits = value;
if (digits <= 0)
{
digits = 0;
}
if (digits > 15)
{
digits = 15;
}
SetValue(DigitsProperty, value);
}
}

private static void OnCurValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
double value = (double)e.NewValue;
NumberBox numericBox = (NumberBox)sender;
numericBox.Text = value.ToString();
}
private static void OnMinValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
double minValue = (double)e.NewValue;
NumberBox numericBox = (NumberBox)sender;
numericBox.MinValue = minValue;
}
private static void OnMaxValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
double maxValue = (double)e.NewValue;
NumberBox numericBox = (NumberBox)sender;
numericBox.MaxValue = maxValue;
}
private static void OnDigitsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
int digits = (int)e.NewValue;
NumberBox numericBox = (NumberBox)sender;
numericBox.CurValue = Math.Round(numericBox.CurValue, digits);
numericBox.MinValue = Math.Round(numericBox.MinValue, digits);
numericBox.MaxValue = Math.Round(numericBox.MaxValue, digits);
}
#endregion


void NumberBox_TextChanged(object sender, TextChangedEventArgs e)
{
NumberBox numericBox = sender as NumberBox;
if (string.IsNullOrEmpty(numericBox.Text))
{
return;
}

TrimZeroStart();

double value = MinValue;
if (!Double.TryParse(numericBox.Text, out value))
{
return;
}

if (value != this.CurValue)
{
this.CurValue = value;
}
}

void NumberBox_KeyDown(object sender, KeyEventArgs e)
{
Key key = e.Key;
if (IsControlKeys(key))
{
return;
}
else if (IsDigit(key))
{
return;
}
else if (IsSubtract(key)) //-
{
TextBox textBox = sender as TextBox;
string str = textBox.Text;
if (str.Length > 0 && textBox.SelectionStart != 0)
{
e.Handled = true;
}
}
else if (IsDot(key)) //point
{
if (this.Digits > 0)
{
TextBox textBox = sender as TextBox;
string str = textBox.Text;
if (str.Contains('.') || str == "-")
{
e.Handled = true;
}
}
else
{
e.Handled = true;
}
}
else
{
e.Handled = true;
}
}

void NumberBox_LostFocus(object sender, RoutedEventArgs e)
{
NumberBox numericBox = sender as NumberBox;
if (string.IsNullOrEmpty(numericBox.Text))
{
numericBox.Text = this.CurValue.ToString();
}
}

private void NumberBox_Pasting(object sender, DataObjectPastingEventArgs e)
{
e.CancelCommand();
}

private static readonly List<Key> _controlKeys = new List<Key>
{
Key.Back,
Key.CapsLock,
Key.Down,
Key.End,
Key.Enter,
Key.Escape,
Key.Home,
Key.Insert,
Key.Left,
Key.PageDown,
Key.PageUp,
Key.Right,
Key.Tab,
Key.Up
};
public static bool IsControlKeys(Key key)
{
return _controlKeys.Contains(key);
}

public static bool IsDigit(Key key)
{
bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0;
bool retVal;
if (key >= Key.D0 && key <= Key.D9 && !shiftKey)
{
retVal = true;
}
else
{
retVal = key >= Key.NumPad0 && key <= Key.NumPad9;
}
return retVal;
}


public static bool IsDot(Key key)
{
bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0;
bool flag = false;
if (key == Key.Decimal)
{
flag = true;
}
if (key == Key.OemPeriod && !shiftKey)
{
flag = true;
}
return flag;
}
public static bool IsSubtract(Key key)
{
bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0;
bool flag = false;
if (key == Key.Subtract)
{
flag = true;
}
if (key == Key.OemMinus && !shiftKey)
{
flag = true;
}
return flag;
}

private void TrimZeroStart()
{
if (this.Text.Length == 1)
{
return;
}
string resultText = this.Text;
int zeroCount = 0;
foreach (char c in this.Text)
{
if (c == '0') { zeroCount++; }
else { break; }
}
if (zeroCount == 0)
{
return;
}

if (this.Text.Contains('.'))
{
if (this.Text[zeroCount] != '.')
{
resultText = this.Text.TrimStart('0');
}
else if (zeroCount > 1)
{
resultText = this.Text.Substring(zeroCount - 1);
}
}
else if (zeroCount > 0)
{
resultText = this.Text.TrimStart('0');
}
}

}
}

+ 101
- 0
BeDesignerSCADA/CustomerControls/StatusLight.cs Переглянути файл

@@ -0,0 +1,101 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
public class StatusLight : Control, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public StatusLight()
{
Width = 80;
Height = 80;
}
public string ControlType => "控件";

static StatusLight()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(StatusLight), new FrameworkPropertyMetadata(typeof(StatusLight)));
}

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

/// <summary>
/// 状态值
/// </summary>
[Category("值设定")]
public int StatusValue
{
get { return (int)GetValue(StatusValueProperty); }
set { SetValue(StatusValueProperty, value); }
}
public static readonly DependencyProperty StatusValueProperty =
DependencyProperty.Register("StatusValue", typeof(int), typeof(StatusLight), new UIPropertyMetadata(0, OnStatusChanged));

private static void OnStatusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as StatusLight).Refresh();

private void Refresh()
{
if (image != null)
{
switch (StatusValue)
{
case 0:
image.Source = new BitmapImage(new Uri("pack://application:,,,/Images/State0.png", UriKind.Absolute));
break;
case -1:
image.Source = new BitmapImage(new Uri("pack://application:,,,/Images/State11.png", UriKind.Absolute));
break;
case 1:
image.Source = new BitmapImage(new Uri("pack://application:,,,/Images/State1.png", UriKind.Absolute));
break;
case 2:
image.Source = new BitmapImage(new Uri("pack://application:,,,/Images/State2.png", UriKind.Absolute));
break;
default:
break;
}
}
}

Image image;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
image = GetTemplateChild("ima") as Image;
Refresh();
}

public void Register()
{
}
}
}

+ 150
- 0
BeDesignerSCADA/CustomerControls/SwitchButton.cs Переглянути файл

@@ -0,0 +1,150 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;


namespace BeDesignerSCADA.CustomerControls
{
[TemplatePart(Name = ELLIPSE, Type = typeof(FrameworkElement))]
[TemplatePart(Name = TranslateX, Type = typeof(TranslateTransform))]
public class SwitchButton : ToggleButton, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public SwitchButton()
{
SetCurrentValue(WidthProperty, 120d);
SetCurrentValue(HeightProperty, 40d);
}

public const string ELLIPSE = "ELLIPSE";
public const string TranslateX = "TranslateX";
static SwitchButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SwitchButton), new FrameworkPropertyMetadata(typeof(SwitchButton)));
}

/// <summary>
/// 不勾选时执行代码
/// </summary>
[Category("事件")]
public string UnCheckedExec
{
get { return (string)GetValue(UnCheckedExecProperty); }
set { SetValue(UnCheckedExecProperty, value); }
}
public static readonly DependencyProperty UnCheckedExecProperty =
DependencyProperty.Register("UnCheckedExec", typeof(string), typeof(SwitchButton), new PropertyMetadata(string.Empty));

/// <summary>
/// 勾选时执行代码
/// </summary>
[Category("事件")]
public string CheckedExec
{
get { return (string)GetValue(CheckedExecProperty); }
set { SetValue(CheckedExecProperty, value); }
}
public static readonly DependencyProperty CheckedExecProperty =
DependencyProperty.Register("CheckedExec", typeof(string), typeof(SwitchButton), new PropertyMetadata(string.Empty));

protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
ellipse.Width = Height - 8;
ellipse.Height = Height - 8;
Refresh();
}

TranslateTransform transX;
Ellipse ellipse;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
ellipse = GetTemplateChild(ELLIPSE) as Ellipse;
transX = GetTemplateChild(TranslateX) as TranslateTransform;
}
protected override void OnChecked(RoutedEventArgs e)
{
base.OnChecked(e);
Refresh();
}
protected override void OnUnchecked(RoutedEventArgs e)
{
base.OnUnchecked(e);
Refresh();
}

void Refresh()
{
if (ellipse == null)
{
return;
}
DoubleAnimation da = new DoubleAnimation();
da.Duration = new Duration(TimeSpan.FromMilliseconds(250));
da.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
if (IsChecked == true)
{
da.To = ActualWidth - ellipse.ActualWidth - 5;
ellipse.SetCurrentValue(Ellipse.FillProperty, Background);
}
else
{
da.To = 3;
ellipse.SetCurrentValue(Ellipse.FillProperty, Brushes.Gray);
}

transX.BeginAnimation(TranslateTransform.XProperty, da);
}

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

public void Register()
{
Checked += TheCheckBox_Checked;
Unchecked += TheCheckBox_Unchecked;
}
private void TheCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
Config.GetInstance().RunJsScipt(UnCheckedExec);
}

private void TheCheckBox_Checked(object sender, RoutedEventArgs e)
{
Config.GetInstance().RunJsScipt(CheckedExec);
}
public string ControlType => "控件";

}


}

+ 9
- 0
BeDesignerSCADA/CustomerControls/TheButton.xaml Переглянути файл

@@ -0,0 +1,9 @@
<Button x:Class="BeDesignerSCADA.CustomerControls.TheButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
</Button>

+ 77
- 0
BeDesignerSCADA/CustomerControls/TheButton.xaml.cs Переглянути файл

@@ -0,0 +1,77 @@

using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// TheButton.xaml 的交互逻辑
/// </summary>
public partial class TheButton : Button, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public TheButton()
{
InitializeComponent();
Content = "按钮";
Width = 80;
Height = 30;
Style = Application.Current.Resources["DesignButton"] as Style;//FindResource("DesignButton") as Style;
}

public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Style = null;
Register();
}
}
}

[Category("事件")]
public string ClickExec
{
get { return (string)GetValue(ClickExecProperty); }
set { SetValue(ClickExecProperty, value); }
}
public static readonly DependencyProperty ClickExecProperty =
DependencyProperty.Register("ClickExec", typeof(string), typeof(TheButton), new PropertyMetadata(string.Empty));

/// <summary>
/// 注册需要处理的事件
/// </summary>
public void Register()
{
this.Click += MyButton_Click;
}

private void MyButton_Click(object sender, RoutedEventArgs e)
{
Config.GetInstance().RunJsScipt(ClickExec);
}
}
}

+ 9
- 0
BeDesignerSCADA/CustomerControls/TheCheckBox.xaml Переглянути файл

@@ -0,0 +1,9 @@
<CheckBox x:Class="BeDesignerSCADA.CustomerControls.TheCheckBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
</CheckBox>

+ 92
- 0
BeDesignerSCADA/CustomerControls/TheCheckBox.xaml.cs Переглянути файл

@@ -0,0 +1,92 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// TheCheckBox.xaml 的交互逻辑
/// </summary>
public partial class TheCheckBox : CheckBox, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public TheCheckBox()
{
InitializeComponent();
Content = "勾选框";
VerticalContentAlignment = VerticalAlignment.Center;
}

public string ControlType => "控件";


private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

/// <summary>
/// 不勾选时执行代码
/// </summary>
[Category("事件")]
public string UnCheckedExec
{
get { return (string)GetValue(UnCheckedExecProperty); }
set { SetValue(UnCheckedExecProperty, value); }
}
public static readonly DependencyProperty UnCheckedExecProperty =
DependencyProperty.Register("UnCheckedExec", typeof(string), typeof(TheCheckBox), new PropertyMetadata(string.Empty));

/// <summary>
/// 勾选时执行代码
/// </summary>
[Category("事件")]
public string CheckedExec
{
get { return (string)GetValue(CheckedExecProperty); }
set { SetValue(CheckedExecProperty, value); }
}
public static readonly DependencyProperty CheckedExecProperty =
DependencyProperty.Register("CheckedExec", typeof(string), typeof(TheCheckBox), new PropertyMetadata(string.Empty));

public void Register()
{
Checked += TheCheckBox_Checked;
Unchecked += TheCheckBox_Unchecked;
}

private void TheCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
Config.GetInstance().RunJsScipt(UnCheckedExec);
}

private void TheCheckBox_Checked(object sender, RoutedEventArgs e)
{
Config.GetInstance().RunJsScipt(CheckedExec);
}
}
}

+ 9
- 0
BeDesignerSCADA/CustomerControls/TheComboBox.xaml Переглянути файл

@@ -0,0 +1,9 @@
<ComboBox x:Class="BeDesignerSCADA.CustomerControls.TheComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
</ComboBox>

+ 75
- 0
BeDesignerSCADA/CustomerControls/TheComboBox.xaml.cs Переглянути файл

@@ -0,0 +1,75 @@
using BeDesignerSCADA.Speical;
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// TheComboBox.xaml 的交互逻辑
/// </summary>
public partial class TheComboBox : ComboBox, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public TheComboBox()
{
InitializeComponent();
VerticalContentAlignment = VerticalAlignment.Center;
ItemsString = new ItemsList() { "AA", "BB" };
Style = Application.Current.Resources["DesignComboBox"] as Style;
Width = 80;
Height = 30;
Focusable = false;
}
public string ControlType => "控件";

public ItemsList ItemsString
{
get { return (ItemsList)GetValue(ItemsStringProperty); }
set { SetValue(ItemsStringProperty, value); }
}

public static readonly DependencyProperty ItemsStringProperty =
DependencyProperty.Register("ItemsString", typeof(ItemsList), typeof(TheComboBox), new PropertyMetadata(null));

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Focusable = true;
IsEnabled = true;
Register();
Style = null;
}
}
}

public void Register()
{
// 运行时进行项目绑定
Binding binding = new Binding();
binding.RelativeSource = new RelativeSource() { Mode = RelativeSourceMode.Self };
binding.Path = new PropertyPath("ItemsString");
SetBinding(ItemsSourceProperty, binding);
}
}
}

+ 9
- 0
BeDesignerSCADA/CustomerControls/TheGroupBox.xaml Переглянути файл

@@ -0,0 +1,9 @@
<GroupBox x:Class="BeDesignerSCADA.CustomerControls.TheGroupBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
</GroupBox>

+ 58
- 0
BeDesignerSCADA/CustomerControls/TheGroupBox.xaml.cs Переглянути файл

@@ -0,0 +1,58 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// TheGroupBox.xaml 的交互逻辑
/// </summary>
public partial class TheGroupBox : GroupBox, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public TheGroupBox()
{
InitializeComponent();
Width = 150;
Height = 150;
Header = "分组";
}

public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

/// <summary>
/// 注册需要处理的事件
/// </summary>
public void Register()
{
}
}
}

+ 9
- 0
BeDesignerSCADA/CustomerControls/TheImage.xaml Переглянути файл

@@ -0,0 +1,9 @@
<Image x:Class="BeDesignerSCADA.CustomerControls.TheImage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
</Image>

+ 57
- 0
BeDesignerSCADA/CustomerControls/TheImage.xaml.cs Переглянути файл

@@ -0,0 +1,57 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// TheImage.xaml 的交互逻辑
/// </summary>
public partial class TheImage : Image, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public TheImage()
{
InitializeComponent();
Stretch = Stretch.UniformToFill;
SetCurrentValue(SourceProperty, new BitmapImage(new Uri("pack://application:,,,/Images/win.png", UriKind.Absolute)));
Width = 120;
Height = 40;
}

public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

public void Register()
{

}
}
}

+ 59
- 0
BeDesignerSCADA/CustomerControls/TheRadioButton.cs Переглянути файл

@@ -0,0 +1,59 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
public class TheRadioButton : RadioButton, IExecutable, IDisposable
{
public event EventHandler PropertyChange; //声明一个事件

public TheRadioButton()
{
SetCurrentValue(ContentProperty, "单选按钮");
}
static TheRadioButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TheRadioButton), new FrameworkPropertyMetadata(typeof(TheRadioButton)));
}

public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
Style = null;
}
}
}

public void Register()
{

}

public void Dispose()
{
}
}
}

+ 69
- 0
BeDesignerSCADA/CustomerControls/TheSlider.cs Переглянути файл

@@ -0,0 +1,69 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
public class TheSlider : Slider, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

static TheSlider()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TheSlider), new FrameworkPropertyMetadata(typeof(TheSlider)));
}

public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
Style = null;
}
}
}

public string ValueChangedExecute
{
get { return (string)GetValue(ValueChangedExecuteProperty); }
set { SetValue(ValueChangedExecuteProperty, value); }
}
public static readonly DependencyProperty ValueChangedExecuteProperty =
DependencyProperty.Register("ValueChangedExecute", typeof(string), typeof(TheSlider), new PropertyMetadata(string.Empty));


public void Register()
{
ValueChanged += TheSlider_ValueChanged;
}

private void TheSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Config.GetInstance().RunJsScipt(ValueChangedExecute);
}

public void Dispose()
{
}
}
}

+ 9
- 0
BeDesignerSCADA/CustomerControls/TheTextBlock.xaml Переглянути файл

@@ -0,0 +1,9 @@
<TextBlock x:Class="BeDesignerSCADA.CustomerControls.TheTextBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
</TextBlock>

+ 55
- 0
BeDesignerSCADA/CustomerControls/TheTextBlock.xaml.cs Переглянути файл

@@ -0,0 +1,55 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// TheTextBlock.xaml 的交互逻辑
/// </summary>
public partial class TheTextBlock : TextBlock, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public TheTextBlock()
{
InitializeComponent();
Text = "文本块";
Width = 80;
Height = 30;
}

public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

public void Register()
{
}
}
}

+ 61
- 0
BeDesignerSCADA/CustomerControls/TheTextBox.cs Переглянути файл

@@ -0,0 +1,61 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA.CustomerControls
{
public class TheTextBox : TextBox, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

static TheTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TheTextBox), new FrameworkPropertyMetadata(typeof(TheTextBox)));
}

public TheTextBox()
{
Width = 80;
Height = 30;
Text = "0.01";
VerticalContentAlignment = VerticalAlignment.Center;
Style = Application.Current.Resources["DesignTheTextBox"] as Style;//FindResource("DesignTheTextBox") as Style;
Focusable = false;
}
public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
IsEnabled = true;
Focusable = true;
Register();
Style = null;
}
}
}

public void Register()
{
}
}
}

+ 99
- 0
BeDesignerSCADA/CustomerControls/TheTimer.cs Переглянути файл

@@ -0,0 +1,99 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace BeDesignerSCADA.CustomerControls
{
public class TheTimer : Control, IExecutable, IDisposable
{
public event EventHandler PropertyChange; //声明一个事件

public TheTimer()
{
Width = 40;
Height = 40;
}
static TheTimer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TheTimer), new FrameworkPropertyMetadata(typeof(TheTimer)));
}

public string ControlType => "控件";


private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
Style = null;
}
}
}

DispatcherTimer timer = new DispatcherTimer();
public void Register()
{
timer.Interval = TimeSpan.FromMilliseconds(Interval);
timer.Tick += Timer_Tick;
timer.Start();
}

private void Timer_Tick(object sender, EventArgs e)
{
Config.GetInstance().RunJsScipt(TikcExecute);
}

public void Start() => timer.Start();
public void Stop() => timer.Stop();

public void Dispose()
{
timer.Stop();
}

/// <summary>
/// 时间间隔
/// </summary>
public int Interval
{
get { return (int)GetValue(IntervalProperty); }
set { SetValue(IntervalProperty, value); }
}
public static readonly DependencyProperty IntervalProperty =
DependencyProperty.Register("Interval", typeof(int), typeof(TheTimer), new PropertyMetadata(0));


/// <summary>
/// 执行内容
/// </summary>
[Category("事件")]
public string TikcExecute
{
get { return (string)GetValue(TikcExecuteProperty); }
set { SetValue(TikcExecuteProperty, value); }
}
public static readonly DependencyProperty TikcExecuteProperty =
DependencyProperty.Register("TikcExecute", typeof(string), typeof(TheTimer), new PropertyMetadata(string.Empty));
}
}

+ 9
- 0
BeDesignerSCADA/CustomerControls/TheToggleButton.xaml Переглянути файл

@@ -0,0 +1,9 @@
<ToggleButton x:Class="BeDesignerSCADA.CustomerControls.TheToggleButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeDesignerSCADA.CustomerControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
</ToggleButton>

+ 96
- 0
BeDesignerSCADA/CustomerControls/TheToggleButton.xaml.cs Переглянути файл

@@ -0,0 +1,96 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// TheToggleButton.xaml 的交互逻辑
/// </summary>
public partial class TheToggleButton : ToggleButton, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

public TheToggleButton()
{
InitializeComponent();
Content = "开关";
Width = 80;
Height = 30;
Style = Application.Current.Resources["DesignToggleButton"] as Style;//FindResource("DesignToggleButton") as Style;
VerticalContentAlignment = VerticalAlignment.Center;
}

public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Style = Application.Current.Resources["ExecuteToggleButton"] as Style;//FindResource("ExecuteToggleButton") as Style;

Register();
}
}
}

/// <summary>
/// 不勾选时执行代码
/// </summary>
[Category("事件")]
public string UnCheckedExec
{
get { return (string)GetValue(UnCheckedExecProperty); }
set { SetValue(UnCheckedExecProperty, value); }
}
public static readonly DependencyProperty UnCheckedExecProperty =
DependencyProperty.Register("UnCheckedExec", typeof(string), typeof(TheToggleButton), new PropertyMetadata(string.Empty));

/// <summary>
/// 勾选时执行代码
/// </summary>
[Category("事件")]
public string CheckedExec
{
get { return (string)GetValue(CheckedExecProperty); }
set { SetValue(CheckedExecProperty, value); }
}
public static readonly DependencyProperty CheckedExecProperty =
DependencyProperty.Register("CheckedExec", typeof(string), typeof(TheToggleButton), new PropertyMetadata(string.Empty));

public void Register()
{
Checked += TheCheckBox_Checked;
Unchecked += TheCheckBox_Unchecked;
}

private void TheCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
Config.GetInstance().RunJsScipt(UnCheckedExec);
}

private void TheCheckBox_Checked(object sender, RoutedEventArgs e)
{
Config.GetInstance().RunJsScipt(CheckedExec);
}
}
}

+ 187
- 0
BeDesignerSCADA/CustomerControls/WaveProgressBar.cs Переглянути файл

@@ -0,0 +1,187 @@
using BPASmartClient.Compiler;
using BPASmartClient.SCADAControl;
using System;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace BeDesignerSCADA.CustomerControls
{
/// <summary>
/// 波浪进度条
/// </summary>
[TemplatePart(Name = ElementWave, Type = typeof(FrameworkElement))]
[TemplatePart(Name = ElementClip, Type = typeof(FrameworkElement))]
public class WaveProgressBar : RangeBase, IExecutable
{
public event EventHandler PropertyChange; //声明一个事件

private const string ElementWave = "PART_Wave";

private const string ElementClip = "PART_Clip";

private FrameworkElement _waveElement;

private const double TranslateTransformMinY = -20;

private double _translateTransformYRange;

private TranslateTransform _translateTransform;

public WaveProgressBar()
{
Loaded += (s, e) => UpdateWave(Value);
SetCurrentValue(WidthProperty, 200d);
SetCurrentValue(HeightProperty, 200d);
SetCurrentValue(ValueProperty, 50d);
}

static WaveProgressBar()
{
FocusableProperty.OverrideMetadata(typeof(WaveProgressBar),
new FrameworkPropertyMetadata(ValueBoxes.FalseBox));
MaximumProperty.OverrideMetadata(typeof(WaveProgressBar),
new FrameworkPropertyMetadata(ValueBoxes.Double100Box));
}

protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);

UpdateWave(newValue);
}

private void UpdateWave(double value)
{
if (_translateTransform == null || IsVerySmall(Maximum)) return;
var scale = 1 - value / Maximum;
var y = _translateTransformYRange * scale + TranslateTransformMinY;
_translateTransform.Y = y;
}

public static bool IsVerySmall(double value) => Math.Abs(value) < 1E-06;

public override void OnApplyTemplate()
{
base.OnApplyTemplate();

_waveElement = GetTemplateChild(ElementWave) as FrameworkElement;
var clipElement = GetTemplateChild(ElementClip) as FrameworkElement;

if (_waveElement != null && clipElement != null)
{
_translateTransform = new TranslateTransform
{
Y = clipElement.Height
};
_translateTransformYRange = clipElement.Height - TranslateTransformMinY;
_waveElement.RenderTransform = new TransformGroup
{
Children = { _translateTransform }
};
}
}

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof(string), typeof(WaveProgressBar), new PropertyMetadata(default(string)));

public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}

public static readonly DependencyProperty ShowTextProperty = DependencyProperty.Register(
"ShowText", typeof(bool), typeof(WaveProgressBar), new PropertyMetadata(ValueBoxes.TrueBox));

public bool ShowText
{
get => (bool)GetValue(ShowTextProperty);
set => SetValue(ShowTextProperty, ValueBoxes.BooleanBox(value));
}

public static readonly DependencyProperty WaveFillProperty = DependencyProperty.Register(
"WaveFill", typeof(Brush), typeof(WaveProgressBar), new PropertyMetadata(default(Brush)));

public Brush WaveFill
{
get => (Brush)GetValue(WaveFillProperty);
set => SetValue(WaveFillProperty, value);
}

public static readonly DependencyProperty WaveThicknessProperty = DependencyProperty.Register(
"WaveThickness", typeof(double), typeof(WaveProgressBar), new PropertyMetadata(ValueBoxes.Double0Box));

public double WaveThickness
{
get => (double)GetValue(WaveThicknessProperty);
set => SetValue(WaveThicknessProperty, value);
}

public static readonly DependencyProperty WaveStrokeProperty = DependencyProperty.Register(
"WaveStroke", typeof(Brush), typeof(WaveProgressBar), new PropertyMetadata(default(Brush)));

public Brush WaveStroke
{
get => (Brush)GetValue(WaveStrokeProperty);
set => SetValue(WaveStrokeProperty, value);
}

public string ControlType => "控件";

private bool isExecuteState;
public bool IsExecuteState
{
get { return isExecuteState; }
set
{
isExecuteState = value;
if (IsExecuteState)
{
Register();
}
}
}

public void Register()
{
}
}

internal static class ValueBoxes
{
internal static object TrueBox = true;

internal static object FalseBox = false;

internal static object Double0Box = .0;

internal static object Double01Box = .1;

internal static object Double1Box = 1.0;

internal static object Double10Box = 10.0;

internal static object Double20Box = 20.0;

internal static object Double100Box = 100.0;

internal static object Double200Box = 200.0;

internal static object Double300Box = 300.0;

internal static object DoubleNeg1Box = -1.0;

internal static object Int0Box = 0;

internal static object Int1Box = 1;

internal static object Int2Box = 2;

internal static object Int5Box = 5;

internal static object Int99Box = 99;

internal static object BooleanBox(bool value) => value ? TrueBox : FalseBox;
}
}




+ 76
- 0
BeDesignerSCADA/Helper/Config.cs Переглянути файл

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Unvell.ReoScript;

namespace BeDesignerSCADA.Helper
{
internal class Config
{
private static ScriptRunningMachine srm { get; } = new ScriptRunningMachine();

static Config()
{
srm.WorkMode |=
// Enable DirectAccess
MachineWorkMode.AllowDirectAccess
// Ignore exceptions in CLR calling (by default)
| MachineWorkMode.IgnoreCLRExceptions
// Enable CLR Event Binding
| MachineWorkMode.AllowCLREventBind;

RegisterFunction();
}

/// <summary>
/// 运行脚本
/// </summary>
/// <param name="script"></param>
public static void RunJsScipt(string script)
{
try
{
srm.Run(script);
}
catch (Exception e)
{
MessageBox.Show(e.Message, "脚本错误");
}
}

/// <summary>
/// 注册对象到js
/// </summary>
public static void SetVariable(string name, object obj)
{
srm.SetGlobalVariable(name, obj);
}

/// <summary>
/// 注册方法到Js
/// </summary>
private static void RegisterFunction()
{
srm["ShowMessage"] = new NativeFunctionObject("ShowMessage", (ctx, owner, args) =>
{
StringBuilder sb = new StringBuilder();
foreach (var item in args)
{
sb.Append(item.ToString());
}

MessageBox.Show($"{sb}", "提示");
return null;
});

srm["SetICDValue"] = new NativeFunctionObject("SetICDValue", (ctx, owner, args) =>
{
MessageBox.Show($"发送ICD数据", "提示");
return null;
});
}
}
}
















+ 296
- 0
BeDesignerSCADA/MainWindow.xaml Переглянути файл

@@ -0,0 +1,296 @@
<Window x:Name="window" x:Class="BeDesignerSCADA.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BeDesignerSCADA"
xmlns:s="clr-namespace:BeDesignerSCADA.Converters"
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:avae="http://icsharpcode.net/sharpdevelop/avalonedit"
xmlns:ctl="clr-namespace:BeDesignerSCADA.Controls"
xmlns:mypro="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="黑菠萝科技-[组态软件1.0]" Height="900" Width="1400" Icon="/Images/ico.ico" >

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/BeDesignerSCADA;component/Themes/Styles.xaml" />
<ResourceDictionary Source="/BPASmartClient.SCADAControl;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240"/>
<ColumnDefinition/>
<ColumnDefinition Width="350"/>
</Grid.ColumnDefinitions>
<!--<icon:PackIconMaterial x:Name="icon" Kind="LineScan" BorderThickness="1" VerticalAlignment="Stretch" Width="24" HorizontalAlignment="Stretch"/>-->
<!--左侧控件栏-->
<Border BorderThickness="1" BorderBrush="{StaticResource AccentBrush}" Margin="4">
<ListBox x:Name="CtlList" Background="Transparent" ItemTemplate="{DynamicResource ToolBoxStyle}" BorderThickness="0" PreviewMouseMove="CtlList_PreviewMouseMove">
</ListBox>
</Border>

<!--中间控制区域-->
<DockPanel Grid.Column="1">
<!--按钮控制-->
<DockPanel LastChildFill="False" DockPanel.Dock="Top" Height="24" Margin="4 4 4 0">
<Button Margin="0" Width="24" Padding="0" Click="AglinLeftBtn_Click" ToolTip="左对齐">
<icon:PackIconModern Kind="AlignLeft"/>
</Button>
<Button Margin="4 0 0 0" Width="24" Padding="0" Click="AglinRightBtn_Click" ToolTip="右对齐">
<icon:PackIconModern Kind="AlignRight"/>
</Button>
<Button Margin="4 0 0 0" Width="24" Padding="0" Click="AglinCenterBtn_Click" ToolTip="中心对齐">
<icon:PackIconModern Kind="AlignCenter"/>
</Button>
<Button Margin="4 0 0 0" Width="24" Padding="0" Click="AglinTopBtn_Click" ToolTip="上对齐">
<icon:PackIconModern Kind="BorderTop"/>
</Button>
<Button Margin="4 0 0 0" Width="24" Padding="0" Click="AglinBottomBtn_Click" ToolTip="下对齐">
<icon:PackIconModern Kind="BorderBottom"/>
</Button>
<Button Margin="16 0 0 0" Width="24" Padding="0" Click="HorizontalLayoutBtn_Click" ToolTip="水平分布">
<icon:PackIconModern Kind="BorderHorizontal"/>
</Button>
<Button Margin="4 0 0 0" Width="24" Padding="0" Click="VerticalLayoutBtn_Click" ToolTip="垂直分布">
<icon:PackIconModern Kind="BorderVertical"/>
</Button>

<ToggleButton IsChecked="{Binding UseAutoAlignment, ElementName=cav, Mode=TwoWay}" ToolTip="使用对齐网格" Margin="4 0 0 0" Width="24" Padding="0">
<icon:PackIconModern Kind="CellAlign"/>
</ToggleButton>

<Button Margin="16 0 0 0" Width="24" Padding="0" ToolTip="复制" Command="{Binding ElementName=cav, Path=CopySelectItemsCommand}">
<icon:PackIconModern Kind="PageCopy"/>
</Button>
<Button Margin="4 0 0 0" Width="24" Padding="0" ToolTip="粘贴" Command="{Binding ElementName=cav, Path=PasteSelectItemsCommand}">
<icon:PackIconModern Kind="ClipboardPaste"/>
</Button>
<Button Margin="4 0 0 0" Width="24" Padding="0" ToolTip="删除" Command="{Binding ElementName=cav, Path=DeleteSelectItemsCommand}">
<icon:PackIconModern Kind="Delete"/>
</Button>

<Button x:Name="RunBtn" Margin="16 0 0 0" Padding="0" Click="RunBtn_Click" Command="{Binding RunUiCommand}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Tag" Value="运行"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Horizontal" Margin="8 0">
<icon:PackIconModern Kind="ControlPlay" VerticalAlignment="Center" Foreground="#28B60F" Width="8"/>
<TextBlock Text="运行" Margin="4 0" VerticalAlignment="Center"/>
</StackPanel>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsRunning}" Value="True">
<Setter Property="Tag" Value="停止"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Horizontal" Margin="8 0">
<icon:PackIconModern Kind="ControlStop" VerticalAlignment="Center" Foreground="#B60F0F" Width="8"/>
<TextBlock Text="停止" Margin="4 0" VerticalAlignment="Center"/>
</StackPanel>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

<Button x:Name="SaveBtn" Margin="16 0 0 0" Padding="0" Click="SaveBtn_Click">
<StackPanel Orientation="Horizontal" Margin="8 0">
<icon:PackIconModern Kind="Save" VerticalAlignment="Center" Width="12"/>
<TextBlock Text="保存" Margin="4 0" VerticalAlignment="Center"/>
</StackPanel>
</Button>

<Button x:Name="LoadBtn" Margin="4 0 0 0" Padding="0" Click="LoadBtn_Click">
<StackPanel Orientation="Horizontal" Margin="8 0">
<icon:PackIconModern Kind="DiskDownload" VerticalAlignment="Center" Width="14"/>
<TextBlock Text="加载" Margin="4 0" VerticalAlignment="Center"/>
</StackPanel>
</Button>

<Button x:Name="MNBtn" Margin="4 0 0 0" Padding="0" Click="MNBtn_Click">
<StackPanel Orientation="Horizontal" Margin="8 0">
<icon:PackIconModern Kind="MessageSend" VerticalAlignment="Center" Width="14"/>
<TextBlock Text="模拟消息" Margin="4 0" VerticalAlignment="Center"/>
</StackPanel>
</Button>

<ToggleButton x:Name="showCode" Click="showCode_Click" DockPanel.Dock="Right" Margin="4 0 0 0" Padding="4 0">
<icon:Material Kind="FileCode"/>
</ToggleButton>

<Slider DockPanel.Dock="Right" Width="100" Maximum="16" Minimum="1" Margin="4 0 0 0"
HorizontalContentAlignment="Center" Value="{Binding ElementName=cav,Path=GridPxiel}" ></Slider>
<TextBlock DockPanel.Dock="Right" Text="对齐:" VerticalAlignment="Center" Margin="16 0 0 0"/>

</DockPanel>

<!--中间画布-->
<Border BorderThickness="1" BorderBrush="{StaticResource AccentBrush}" Margin="4">
<Border.Background>
<ImageBrush ImageSource="/Images/bj.png" Stretch="UniformToFill"/>
</Border.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>

<ctl:CanvasPanel x:Name="cav" Visibility="{Binding CanvasPanelVisibility}" SelectedItem="{Binding CanSelectedItem,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" AllowDrop="True" RenderTransformOrigin="0.5,0.5" ClipToBounds="True" UseLayoutRounding="True" Focusable="True" SnapsToDevicePixels="True">
<ctl:CanvasPanel.Background>
<VisualBrush TileMode="Tile" Viewport="0,0,20,20" ViewportUnits="Absolute">
<VisualBrush.Visual>
<Rectangle Width="20" Height="20" StrokeDashArray="4,2" StrokeThickness="0.5" Stroke="#CBCBCB">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Style.Triggers>
<DataTrigger Binding="{Binding UseAutoAlignment, RelativeSource={RelativeSource AncestorType={x:Type ctl:CanvasPanel}, Mode=FindAncestor}}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding UseAutoAlignment, RelativeSource={RelativeSource AncestorType={x:Type ctl:CanvasPanel}, Mode=FindAncestor}}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</VisualBrush.Visual>
</VisualBrush>
</ctl:CanvasPanel.Background>

<ctl:CanvasPanel.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="CanvasTranslate"/>
</TransformGroup>
</ctl:CanvasPanel.RenderTransform>
</ctl:CanvasPanel>


<ctl:RunCanvas x:Name="runCanvas" Visibility="{Binding RunCanvasVisibility}" >
</ctl:RunCanvas>

<avae:TextEditor x:Name="codeEditor" ShowLineNumbers="True" Padding="4" WordWrap="True" IsReadOnly="True" SyntaxHighlighting="XML" BorderThickness="1 0 0 0" BorderBrush="{StaticResource ControlBorderBrush}" Grid.Column="1" Width="480" Visibility="{Binding ElementName=showCode, Path=IsChecked, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"/>
</Grid>
</Border>
</DockPanel>

<GridSplitter HorizontalAlignment="Right" Grid.Column="1" VerticalAlignment="Stretch" Width="5" Background="Transparent"/>

<!--右侧属性栏-->
<Grid Grid.Column="2">
<TabControl SelectedIndex="0">
<TabItem Header="控制协议">
<mypro:PropertyGrid x:Name="kzxy" SelectedObject="{Binding PropeObject}"
Margin="10" ShowAdvancedOptions="True" ShowDescriptionByTooltip="True"
FontSize="14" ShowTitle="False" ShowSortOptions="False" ShowSearchBox="False"
CategoryGroupHeaderTemplate="{DynamicResource Category}">
<mypro:PropertyGrid.EditorDefinitions>
<!--EditorTemplateDefinition可添加多个-->
<!--要修改编辑模板的属性的名称-->
<mypro:EditorTemplateDefinition TargetProperties="点击事件,值改变事件,定时触发,勾选事件,取消勾选事件" >
<mypro:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<!--此处可自由发挥-->
<Grid>
<!-- Command生效: DataTemplate的DataContext指代不明确,需要改为父类的DataContext。 参数Value表示原对象-->
<!--Command="{Binding Path=DataContext.PropeSetCommand ,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=xctk:PropertyGrid}}"-->
<!--DataContext="{Binding DataContext, ElementName=window}" Command="{Binding PropeSetCommand}" CommandParameter="{Binding Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" x:Name="key"/>
<ColumnDefinition Width="35"/>
</Grid.ColumnDefinitions>
<TextBox Width="{Binding Width, ElementName=key}" Text="{Binding Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TextWrapping="Wrap"></TextBox>
<ToggleButton Grid.Column="1" Height="25" Content="编辑" Width="30" HorizontalAlignment="Left" Click="ToggleButton_Click"></ToggleButton>
</Grid>
</DataTemplate>
</mypro:EditorTemplateDefinition.EditingTemplate>
</mypro:EditorTemplateDefinition>

<mypro:EditorTemplateDefinition TargetProperties="代码过滤脚本" >
<mypro:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<!--此处可自由发挥-->
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBox Text="{Binding Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" AcceptsReturn="True" TextWrapping="Wrap"></TextBox>
</ScrollViewer>
</DataTemplate>
</mypro:EditorTemplateDefinition.EditingTemplate>
</mypro:EditorTemplateDefinition>

<mypro:EditorTemplateDefinition TargetProperties="设备解析变量" >
<mypro:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<!--此处可自由发挥-->
<Grid>
<ComboBox Grid.Column="1" Height="25" Width="{Binding Width, ElementName=com}" Text="{Binding Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window},Path=DataContext.DevValueList}"
></ComboBox>
</Grid>
</DataTemplate>
</mypro:EditorTemplateDefinition.EditingTemplate>
</mypro:EditorTemplateDefinition>

<mypro:EditorTemplateDefinition TargetProperties="设备名称" >
<mypro:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<!--此处可自由发挥-->
<Grid>
<ComboBox Grid.Column="1" Height="25" Width="{Binding Width, ElementName=com}" Text="{Binding Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window},Path=DataContext.DevNameList}"
></ComboBox>
</Grid>
</DataTemplate>
</mypro:EditorTemplateDefinition.EditingTemplate>
</mypro:EditorTemplateDefinition>

<mypro:EditorTemplateDefinition TargetProperties="文本,文本1,标题,变量" >
<mypro:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<!--此处可自由发挥-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Margin="0,5,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" x:Name="key"/>
<ColumnDefinition Width="*" x:Name="Text"/>
</Grid.ColumnDefinitions>
<TextBlock>绑定:</TextBlock>
<ComboBox x:Name="namebox" DropDownOpened="namebox_DropDownOpened" Grid.Column="1" Height="25" IsTextSearchEnabled="True" IsEditable="True" Tag="{Binding Text, ElementName=valuebox}" Width="{Binding Width, ElementName=key}" TextBoxBase.TextChanged="ComboBoxName_TextChanged"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window},Path=DataContext.DevNameList}">
</ComboBox>
<ComboBox x:Name="valuebox" DropDownOpened="valuebox_DropDownOpened" Grid.Column="2" Height="25" IsTextSearchEnabled="True" IsEditable="True" Tag="{Binding Text, ElementName=namebox}" Width="{Binding Width, ElementName=Text}" TextBoxBase.TextChanged="ComboBoxValue_TextChanged"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window},Path=DataContext.DevValueList}"/>
</Grid>
<TextBox Grid.Row="2" x:Name="wenben" Width="{Binding Width, ElementName=Text}" Padding="5" Text="{Binding Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TextWrapping="Wrap"></TextBox>
</Grid>
</DataTemplate>
</mypro:EditorTemplateDefinition.EditingTemplate>
</mypro:EditorTemplateDefinition>
</mypro:PropertyGrid.EditorDefinitions>
</mypro:PropertyGrid>
</TabItem>
<TabItem Header="控件样式">
<mypro:PropertyGrid x:Name="dsdsdsd"
Margin="10" ShowAdvancedOptions="True" ShowDescriptionByTooltip="True"
FontSize="14" ShowTitle="False" ShowSortOptions="False" ShowSearchBox="False"
CategoryGroupHeaderTemplate="{DynamicResource Category}" SelectedObject="{Binding SelectedItem,ElementName=cav,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</TabItem>
</TabControl>
</Grid>
</Grid>
</Window>

+ 441
- 0
BeDesignerSCADA/MainWindow.xaml.cs Переглянути файл

@@ -0,0 +1,441 @@
using BeDesignerSCADA.ViewModel;
using BPASmart.Model;
using BPASmartClient.Compiler;
using BPASmartClient.DATABUS;
using BPASmartClient.MessageName;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BeDesignerSCADA
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
MainViewModel viewModel=new MainViewModel();
public MainWindow()
{
InitializeComponent();
//Loading();
this.DataContext = viewModel;
viewModel.Loaded(cav);
//控件加载
Assembly assembly = Assembly.LoadFile($"{System.AppDomain.CurrentDomain.BaseDirectory}\\BPASmartClient.SCADAControl.dll");
//Assembly assembly = Assembly.GetExecutingAssembly();
var controls = assembly.GetTypes().Where(t => t.GetInterface("IExecutable") != null);
CtlList.ItemsSource = controls;
viewModel.propertyGrid = kzxy;
//LoadFile();
}

#region 加载数据中心与事件中心
public void Loading()
{
//try
//{
// Assembly assembly1 = Assembly.LoadFile($"{System.AppDomain.CurrentDomain.BaseDirectory}\\BPASmartClient.MessageName.dll");
// Type type = assembly1.GetType("BPASmartClient.MessageName.MessageName");
// var control = Activator.CreateInstance(type);
// var fildes = control.GetType().GetFields();
// foreach (var fi in fildes)
// {
// EventModel eventModel = new EventModel();
// eventModel.EventValue = fi.GetValue(control)?.ToString();
// eventModel.EventName = fi.Name;
// foreach (var item in fi.CustomAttributes)
// {
// if (item.AttributeType.Name == "CategoryAttribute")
// {
// eventModel.Category = item.ConstructorArguments.Count() > 0 ? item.ConstructorArguments[0].Value?.ToString() : "";
// }
// else if (item.AttributeType.Name == "DescriptionAttribute")
// {
// eventModel.Description = item.ConstructorArguments.Count() > 0 ? item.ConstructorArguments[0].Value?.ToString() : "";
// }
// else if (item.AttributeType.Name == "BrowsableAttribute")
// {
// eventModel.Browsable = item.ConstructorArguments.Count() > 0 ? (bool)item.ConstructorArguments[0].Value : true;
// }
// }
// if (!string.IsNullOrEmpty(eventModel.Category))
// {
// if (Class_DataBus.GetInstance().EventData.ContainsKey(eventModel.Category))
// Class_DataBus.GetInstance().EventData[eventModel.Category].Add(eventModel);
// else
// {
// Class_DataBus.GetInstance().EventData[eventModel.Category] = new List<EventModel> { eventModel };
// }
// }
// }


// type = assembly1.GetType("BPASmartClient.MessageName.DataName");
// control = Activator.CreateInstance(type);
// fildes = control.GetType().GetFields();
// foreach (var fi in fildes)
// {
// ALLModel aLLModel = new ALLModel();
// aLLModel.DataValue = fi.GetValue(control)?.ToString();
// aLLModel.DataName = fi.Name;
// foreach (var item in fi.CustomAttributes)
// {
// if (item.AttributeType.Name == "CategoryAttribute")
// {
// aLLModel.Category = item.ConstructorArguments.Count() > 0 ? item.ConstructorArguments[0].Value?.ToString() : "";
// }
// else if (item.AttributeType.Name == "DescriptionAttribute")
// {
// aLLModel.Description = item.ConstructorArguments.Count() > 0 ? item.ConstructorArguments[0].Value?.ToString() : "";
// }
// else if (item.AttributeType.Name == "BrowsableAttribute")
// {
// aLLModel.Browsable = item.ConstructorArguments.Count() > 0 ? (bool)item.ConstructorArguments[0].Value : true;
// }
// }
// if (!string.IsNullOrEmpty(aLLModel.Category))
// {
// if (Class_DataBus.GetInstance().ALLData.ContainsKey(aLLModel.Category))
// Class_DataBus.GetInstance().ALLData[aLLModel.Category].Add(aLLModel);
// else
// {
// Class_DataBus.GetInstance().ALLData[aLLModel.Category] = new List<ALLModel> { aLLModel };
// }
// }
// }

//}
//catch (Exception ex)
//{
// System.Windows.MessageBox.Show(ex.Message);
//}
}

/// <summary>
/// 加载本地文件
/// </summary>
public void LoadFile()
{
//加载配置数据
FJson<CommunicationPar>.Read();
viewModel.DevNameList = new System.Collections.ObjectModel.ObservableCollection<string>();
viewModel.DevValueList = new System.Collections.ObjectModel.ObservableCollection<string>();
FJson<CommunicationPar>.Data.CommunicationDevices?.ToList().ForEach(data =>
{
viewModel.DevNameList.Add(data.DeviceName);
data.VarTableModels?.ToList().ForEach((data) => {
if(!viewModel.DevValueList.Contains(data.VarName) && !string.IsNullOrEmpty(data.VarName))
viewModel.DevValueList.Add(data.VarName);
});
});
//CommunicationModel model = new CommunicationModel();
//Type typeData = model.GetType();
//PropertyInfo[] properties = typeData.GetProperties();
//foreach (PropertyInfo property in properties)
//{
// viewModel.DevValueList.Add(property.Name);

//}
//ICommunicationDevice DeviceType;
//DeviceType = FJson<CommunicationPar>.Data.CommunicationDevices.ElementAt(0).CommDevice;
//VariableInfo variable = new VariableInfo(DeviceType);
//PropertyInfo[] prope = variable.GetType().GetProperties();
//foreach (var item in prope)
//{
// viewModel.DevValueList.Add(item.Name);
//}
}
#endregion

#region 位置调整
/// <summary>
/// 左对齐
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AglinLeftBtn_Click(object sender, RoutedEventArgs e)
{
cav.AlignLeft();
}
/// <summary>
/// 底部对齐
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AglinBottomBtn_Click(object sender, RoutedEventArgs e)
{
cav.AlignBottom();
}
/// <summary>
/// 顶部对齐
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AglinTopBtn_Click(object sender, RoutedEventArgs e)
{
cav.AlignTop();
}
/// <summary>
/// 右对齐
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AglinRightBtn_Click(object sender, RoutedEventArgs e)
{
cav.AlignRight();
}
/// <summary>
/// 居中
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AglinCenterBtn_Click(object sender, RoutedEventArgs e)
{
cav.AlignCenter();
}
/// <summary>
/// 垂直分布
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void VerticalLayoutBtn_Click(object sender, RoutedEventArgs e)
{
cav.VertialLayout();
}
/// <summary>
/// 水平分布
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HorizontalLayoutBtn_Click(object sender, RoutedEventArgs e)
{
cav.HorizontalLayout();
}
#endregion

#region 其他事件操作
/// <summary>
/// 运行
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RunBtn_Click(object sender, RoutedEventArgs e)
{
if (sender is System.Windows.Controls.Button btn)
{
if (btn.Tag.ToString() == "运行")
{
cav.ClearSelection();
runCanvas.Run(cav.Generator());
}
else if (btn.Tag.ToString() == "停止")
{
runCanvas.Destory();
}
}
}

/// <summary>
/// 加载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void LoadBtn_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "布局文件|*.lay";
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
cav.Load(ofd.FileName);
}

DoubleAnimation da = new DoubleAnimation(-200, 0, new Duration(TimeSpan.FromMilliseconds(250)));
da.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
CanvasTranslate.BeginAnimation(TranslateTransform.XProperty, da);

DoubleAnimation daop = new DoubleAnimation(0, 1, new Duration(TimeSpan.FromMilliseconds(250)));
daop.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
cav.BeginAnimation(OpacityProperty, daop);
}

/// <summary>
/// 保存
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SaveBtn_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "布局文件|*.lay";

if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string str = cav.Save();
File.WriteAllText(sfd.FileName, str, Encoding.Unicode);
}
}

/// <summary>
/// 模拟消息发送
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MNBtn_Click(object sender, RoutedEventArgs e)
{

}
#endregion

#region 左侧控件栏移动
private void CtlList_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (CtlList.SelectedItem != null && e.LeftButton == MouseButtonState.Pressed)
{
DragDrop.DoDragDrop(CtlList, CtlList.SelectedItem, System.Windows.DragDropEffects.Copy);
codeEditor.Text = cav.Save();
}
}

/// <summary>
/// 显示代码
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void showCode_Click(object sender, RoutedEventArgs e)
{
codeEditor.Text = cav.Save();
}

/// <summary>
/// 编辑
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ToggleButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (sender is ToggleButton)
{
ToggleButton toggle = (ToggleButton)sender;
Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem propertyGridCommand = toggle.DataContext as Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem;
if (propertyGridCommand != null)
{
viewModel.Edit(propertyGridCommand);
}
}
}
catch (Exception ex)
{

}
}

/// <summary>
/// 变量编辑
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ComboBoxValue_TextChanged(object sender,TextChangedEventArgs e)
{
try
{
if (sender is System.Windows.Controls.ComboBox)
{
System.Windows.Controls.ComboBox toggle = (System.Windows.Controls.ComboBox)sender;
Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem propertyGridCommand = toggle.DataContext as Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem;
if (toggle.Tag != null)
propertyGridCommand.Value = "{" + $"Binding {toggle.Tag}.{toggle.Text}" + "}";
else
propertyGridCommand.Value = "{" + $"Binding {toggle.Tag}." + "}";
}
}
catch (Exception ex)
{

}
}
private void valuebox_DropDownOpened(object sender,EventArgs e)
{
try
{
viewModel.DevValueList = new System.Collections.ObjectModel.ObservableCollection<string>();

if (sender is System.Windows.Controls.ComboBox)
{
System.Windows.Controls.ComboBox toggle = (System.Windows.Controls.ComboBox)sender;
if (toggle.Tag == null) return;
if (Class_DataBus.GetInstance().Dic_DeviceData.ContainsKey(toggle.Tag.ToString()))
{
Class_DataBus.GetInstance().Dic_DeviceData[toggle.Tag.ToString()].Keys?.ToList().ForEach(key => { viewModel.DevValueList.Add(key); });
}
}
}
catch (Exception ex)
{

}
}
/// <summary>
/// 设备名称选择
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ComboBoxName_TextChanged(object sender,TextChangedEventArgs e)
{
try
{
if (sender is System.Windows.Controls.ComboBox)
{
System.Windows.Controls.ComboBox toggle = (System.Windows.Controls.ComboBox)sender;
Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem propertyGridCommand = toggle.DataContext as Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem;
if(toggle.Tag!=null)
propertyGridCommand.Value = "{" + $"Binding {toggle.Text}.{toggle.Tag}" + "}";
else
propertyGridCommand.Value = "{" + $"Binding {toggle.Text}." + "}";

}
}
catch (Exception ex)
{

}
}


private void namebox_DropDownOpened(object sender,EventArgs e)
{
viewModel.DevNameList = new System.Collections.ObjectModel.ObservableCollection<string>();
Class_DataBus.GetInstance().Dic_DeviceData.Keys?.ToList().ForEach(key => { viewModel.DevNameList.Add(key); });
}
#endregion


}


}

+ 14
- 0
BeDesignerSCADA/Speical/ControlTypeAttribute.cs Переглянути файл

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BeDesignerSCADA.Speical
{
[AttributeUsage(AttributeTargets.Class)]
public class ControlTypeAttribute : Attribute
{
public string Group { get; set; }
}
}

+ 37
- 0
BeDesignerSCADA/Speical/ItemsList.cs Переглянути файл

@@ -0,0 +1,37 @@
using Microsoft.Toolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BeDesignerSCADA.Speical
{
/// <summary>
/// 因ObservableCollection无法序列化,继承并实例化一个
/// </summary>
public class ItemsList : ObservableCollection<string>
{
public ItemsList()
{
AddCommand = new RelayCommand<string>(AddItem);
DeleteCommand = new RelayCommand<string>(DeleteItem);
}

private void DeleteItem(string obj)
{
if (!string.IsNullOrEmpty(obj))
Remove(obj);
}

public RelayCommand<string> AddCommand { get; }
public RelayCommand<string> DeleteCommand { get; }
private void AddItem(string txt)
{
if (!string.IsNullOrEmpty(txt))
Add(txt);
}

}
}

+ 686
- 0
BeDesignerSCADA/Themes/Styles.xaml Переглянути файл

@@ -0,0 +1,686 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:con="clr-namespace:BeDesignerSCADA.Converters"
xmlns:dxmvmm="clr-namespace:BeDesignerSCADA.Converters"
xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
xmlns:ctrl="clr-namespace:BeDesignerSCADA.CustomerControls">
<!--#region 主题笔刷 -->
<LinearGradientBrush x:Key="NormalBackground" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStopCollection>
<GradientStop Color="White" />
<GradientStop Color="#D0D0D0" Offset="0.5"/>
<GradientStop Color="#E3E3E3" Offset="1"/>
</GradientStopCollection>
</LinearGradientBrush>

<SolidColorBrush x:Key="AccentBrush" Color="#2B79E2"/>
<SolidColorBrush x:Key="ControlBorderBrush" Color="LightGray"/>
<SolidColorBrush x:Key="ControlBackground" Color="White"/>
<SolidColorBrush x:Key="ControlForeground" Color="Black"/>
<!--#endregion-->

<!--#region 转换器 -->
<con:HalfNumberConverter x:Key="HalfNumber"/>
<!--#endregion-->
<!--#region 编辑模板 -->
<DataTemplate x:Key="EventEditTemplate">
<DockPanel Height="24">
<Button DockPanel.Dock="Right" Command="{Binding DataContext.EditCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
Content="..." CommandParameter="{Binding .}" Margin="2"/>
<TextBlock Text="{Binding Value}" VerticalAlignment="Center" Margin="4 0 0 0"/>
</DockPanel>
</DataTemplate>

<DataTemplate x:Key="ListEditTemplate">
<DockPanel MaxHeight="100">
<DockPanel DockPanel.Dock="Top">
<Button DockPanel.Dock="Right" Command="{Binding Value.AddCommand}"
CommandParameter="{Binding ElementName=AddTxt, Path=Text}" Margin="2" Padding="2">
<icon:PackIconModern Kind="EditAdd"/>
</Button>
<Button DockPanel.Dock="Right" Command="{Binding Value.DeleteCommand}"
CommandParameter="{Binding ElementName=list, Path=SelectedItem}" Margin="2" Padding="2">
<icon:PackIconModern Kind="Delete" />
</Button>
<TextBox x:Name="AddTxt" Margin="2"/>
</DockPanel>

<ListBox x:Name="list" ItemsSource="{Binding Value}" Margin="2"/>
</DockPanel>
</DataTemplate>

<DataTemplate x:Key="ImagePathEditTemplate">
<DockPanel>
<Button DockPanel.Dock="Right" Content="..." Padding="0" Margin="2" Width="20" Height="20"
Command="{Binding DataContext.SelectPathCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}" CommandParameter="{Binding .}"/>
<TextBox DockPanel.Dock="Right" x:Name="AddTxt" Text="{Binding Value}" BorderThickness="0"/>
</DockPanel>
</DataTemplate>
<!--#endregion-->

<!--#region 为某些获取焦点的控件设计设计时样式 -->
<Style TargetType="ComboBox" x:Key="DesignComboBox">
<Setter Property="Focusable" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Border BorderThickness="1" BorderBrush="{StaticResource ControlBorderBrush}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Border Background="{StaticResource ControlBackground}"/>
<Border Grid.Column="1" Background="{StaticResource ControlBackground}" BorderThickness="0" IsEnabled="False">
<Path Data="M0,0 8,0 4,4z" Fill="{StaticResource ControlForeground}" Margin="3" VerticalAlignment="Center"/>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<!--<Style TargetType="Button" x:Key="DesignButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border BorderThickness="1" BorderBrush="{StaticResource ControlBorderBrush}" Background="{StaticResource ControlBackground}">
<TextBlock Text="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>-->

<Style TargetType="ToggleButton" x:Key="DesignToggleButton">
<Setter Property="Foreground" Value="{StaticResource ControlForeground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border BorderThickness="1" Background="{StaticResource NormalBackground}" BorderBrush="{StaticResource ControlBorderBrush}" CornerRadius="2">
<TextBlock Text="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="ToggleButton" x:Key="ExecuteToggleButton">
<Setter Property="Foreground" Value="{StaticResource ControlForeground}" />
<Setter Property="Foreground" Value="{StaticResource ControlForeground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="bd" BorderThickness="1" Background="{StaticResource NormalBackground}" BorderBrush="{StaticResource ControlBorderBrush}" CornerRadius="2">
<TextBlock Text="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" TargetName="bd">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStopCollection>
<GradientStop Color="#6AD456" />
<GradientStop Color="#1DAE06" Offset="0.5"/>
<GradientStop Color="#8BDC7C" Offset="1"/>
</GradientStopCollection>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--#endregion-->

<DataTemplate x:Key="ToolBoxStyle">
<Grid Margin="2" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<icon:PackIconMaterial x:Name="icon" Kind="Ellipse" BorderThickness="1" VerticalAlignment="Stretch" Width="24" HorizontalAlignment="Stretch"/>
<TextBlock x:Name="txt" Grid.Column="1" Text="{Binding Name}" Margin="4"/>
</Grid>

<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Name}" Value="TheButton">
<Setter Property="Kind" TargetName="icon" Value="GestureTapButton"/>
<Setter Property="Text" TargetName="txt" Value="按钮"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheTimer">
<Setter Property="Kind" TargetName="icon" Value="Timer"/>
<Setter Property="Text" TargetName="txt" Value="计时器"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheCheckBox">
<Setter Property="Kind" TargetName="icon" Value="CheckboxMarked"/>
<Setter Property="Text" TargetName="txt" Value="勾选框"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="DigitalNumber">
<Setter Property="Kind" TargetName="icon" Value="LedStrip"/>
<Setter Property="Text" TargetName="txt" Value="液晶数字"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheComboBox">
<Setter Property="Kind" TargetName="icon" Value="ViewList"/>
<Setter Property="Text" TargetName="txt" Value="下拉框"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheImage">
<Setter Property="Kind" TargetName="icon" Value="Image"/>
<Setter Property="Text" TargetName="txt" Value="图片"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheTextBlock">
<Setter Property="Kind" TargetName="icon" Value="TagText"/>
<Setter Property="Text" TargetName="txt" Value="文本块"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="ArcGauge">
<Setter Property="Kind" TargetName="icon" Value="Gauge"/>
<Setter Property="Text" TargetName="txt" Value="仪表盘"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="StatusLight">
<Setter Property="Kind" TargetName="icon" Value="CeilingLight"/>
<Setter Property="Text" TargetName="txt" Value="状态灯"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheToggleButton">
<Setter Property="Kind" TargetName="icon" Value="CheckOutline"/>
<Setter Property="Text" TargetName="txt" Value="开关按钮"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheGroupBox">
<Setter Property="Kind" TargetName="icon" Value="Group"/>
<Setter Property="Text" TargetName="txt" Value="分组"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheTextBox">
<Setter Property="Kind" TargetName="icon" Value="TextBox"/>
<Setter Property="Text" TargetName="txt" Value="文本框"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="NumberBox">
<Setter Property="Kind" TargetName="icon" Value="Numeric8Box"/>
<Setter Property="Text" TargetName="txt" Value="数值框"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="GraphArrow">
<Setter Property="Kind" TargetName="icon" Value="ArrowRightBold"/>
<Setter Property="Text" TargetName="txt" Value="箭头"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="GraphStar">
<Setter Property="Kind" TargetName="icon" Value="Star"/>
<Setter Property="Text" TargetName="txt" Value="五角星"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheSlider">
<Setter Property="Kind" TargetName="icon" Value="ArrowDownBold"/>
<Setter Property="Text" TargetName="txt" Value="滑块"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheRadioButton">
<Setter Property="Kind" TargetName="icon" Value="RadioboxMarked"/>
<Setter Property="Text" TargetName="txt" Value="单选按钮"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="SwitchButton">
<Setter Property="Kind" TargetName="icon" Value="ToggleSwitch"/>
<Setter Property="Text" TargetName="txt" Value="开关"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="KnobButton">
<Setter Property="Kind" TargetName="icon" Value="Ellipse"/>
<Setter Property="Text" TargetName="txt" Value="旋钮"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="Silos">
<Setter Property="Kind" TargetName="icon" Value="StoreSettings"/>
<Setter Property="Text" TargetName="txt" Value="物料仓"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="NewConveyorBelt">
<Setter Property="Kind" TargetName="icon" Value="ArrowLeftRightBoldOutline"/>
<Setter Property="Text" TargetName="txt" Value="滚动线"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheDataGrid">
<Setter Property="Kind" TargetName="icon" Value="LineScan"/>
<Setter Property="Text" TargetName="txt" Value="表格"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="TheListBox">
<Setter Property="Kind" TargetName="icon" Value="LineScan"/>
<Setter Property="Text" TargetName="txt" Value="列表控件"/>
</DataTrigger>

<DataTrigger Binding="{Binding Name}" Value="TheRedis">
<Setter Property="Kind" TargetName="icon" Value="AlphaDBoxOutline"/>
<Setter Property="Text" TargetName="txt" Value="Redis控件"/>
</DataTrigger>

<DataTrigger Binding="{Binding Name}" Value="WaveProgressBar">
<Setter Property="Kind" TargetName="icon" Value="Wave"/>
<Setter Property="Text" TargetName="txt" Value="进度条波浪"/>
</DataTrigger>

<DataTrigger Binding="{Binding Name}" Value="TheProgressBar">
<Setter Property="Kind" TargetName="icon" Value="LineScan"/>
<Setter Property="Text" TargetName="txt" Value="进度条正常"/>
</DataTrigger>

<DataTrigger Binding="{Binding Name}" Value="TheRedProgressBar">
<Setter Property="Kind" TargetName="icon" Value="LineScan"/>
<Setter Property="Text" TargetName="txt" Value="进度条圆形红"/>
</DataTrigger>

<DataTrigger Binding="{Binding Name}" Value="TheBlueProgressBar">
<Setter Property="Kind" TargetName="icon" Value="LineScan"/>
<Setter Property="Text" TargetName="txt" Value="进度条圆形蓝"/>
</DataTrigger>

<DataTrigger Binding="{Binding Name}" Value="TheGreenProgressBar">
<Setter Property="Kind" TargetName="icon" Value="LineScan"/>
<Setter Property="Text" TargetName="txt" Value="进度条圆形绿"/>
</DataTrigger>

<DataTrigger Binding="{Binding Name}" Value="TheAPI">
<Setter Property="Kind" TargetName="icon" Value="AlphaABoxOutline"/>
<Setter Property="Text" TargetName="txt" Value="API接口"/>
</DataTrigger>

<DataTrigger Binding="{Binding Name}" Value="TheMQTT">
<Setter Property="Kind" TargetName="icon" Value="AlphaMBoxOutline"/>
<Setter Property="Text" TargetName="txt" Value="MQTT"/>
</DataTrigger>

</DataTemplate.Triggers>
</DataTemplate>

<FontFamily x:Key="Digital">
pack://application:,,,/Fonts/#DS-Digital
</FontFamily>

<!--#region 右键菜单-->
<ContextMenu x:Key="CanvasRightMenu" DataContext="{Binding PlacementTarget,RelativeSource={RelativeSource Self}}" FontFamily="Microsoft YaHei Ui">
<MenuItem Header="复制" Command="{Binding CopySelectItemsCommand}">
<MenuItem.Icon>
<icon:PackIconModern Kind="PageCopy" HorizontalAlignment="Center" Width="10"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="粘贴" Command="{Binding PasteSelectItemsCommand}">
<MenuItem.Icon>
<icon:PackIconModern Kind="ClipboardPaste" HorizontalAlignment="Center" Width="10"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="删除" Command="{Binding DeleteSelectItemsCommand}">
<MenuItem.Icon>
<icon:PackIconModern Kind="Delete" HorizontalAlignment="Center" Width="10"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>

<ContextMenu x:Key="AdornerRightMenu" DataContext="{Binding PlacementTarget.Tag,RelativeSource={RelativeSource Mode=Self}}" FontFamily="Microsoft YaHei Ui">
<MenuItem Header="复制" Command="{Binding CopySelectItemsCommand}">
<MenuItem.Icon>
<icon:PackIconModern Kind="PageCopy" HorizontalAlignment="Center" Width="10"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="粘贴" Command="{Binding PasteSelectItemsCommand}">
<MenuItem.Icon>
<icon:PackIconModern Kind="ClipboardPaste" HorizontalAlignment="Center" Width="10"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="删除" Command="{Binding DeleteSelectItemsCommand}">
<MenuItem.Icon>
<icon:PackIconModern Kind="Delete" HorizontalAlignment="Center" Width="10"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="置于顶层" Command="{Binding SetTopLayerCommand}">
<MenuItem.Icon>
<icon:PackIconMaterial Kind="ArrangeSendToBack" HorizontalAlignment="Center" Width="10"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="置于底层" Command="{Binding SetBottomLayerCommand}">
<MenuItem.Icon>
<icon:PackIconMaterial Kind="ArrangeBringToFront" HorizontalAlignment="Center" Width="10"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>

<!--#endregion-->

<!--#region 控件集合-->
<!--<Style TargetType="ctrl:DigitalNumber">
<Setter Property="Background" Value="#FF1A1E22"/>
<Setter Property="Foreground" Value="#FF0AA74D"/>
<Setter Property="NumberValue" Value="0.01"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ctrl:DigitalNumber">
<Grid Background="{TemplateBinding Background}">
<TextBlock x:Name="line" VerticalAlignment="Center" HorizontalAlignment="Center"
FontFamily="{StaticResource Digital}" FontSize="{TemplateBinding FontSize}"
Text="{Binding NumberValue,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ctrl:DigitalNumber},Mode=TwoWay}"
Foreground="{TemplateBinding Foreground}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ctrl:TheTimer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ctrl:TheTimer}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Image Source="../Images/timericon.png" RenderOptions.BitmapScalingMode="Fant"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>


<Style TargetType="{x:Type ctrl:StatusLight}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ctrl:StatusLight}">
<Border Width="{Binding Path=ActualHeight,RelativeSource={RelativeSource Self}}">
<Grid>
<Image x:Name="ima" Source="../Images/State0.png" RenderOptions.BitmapScalingMode="Fant">
</Image>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="{x:Type ctrl:ArcGauge}">
<Setter Property="Background" Value="#646464"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ctrl:ArcGauge}">
<Border Margin="10">
<Grid Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}">
<Ellipse Fill="#FF3B3B3B"/>
<Grid RenderTransformOrigin="0.5,0.5" Margin="2">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform Angle="{Binding Path=Angle,ElementName=PointRotate}"/>
</TransformGroup>
</Grid.RenderTransform>
<Ellipse Width="16" Height="14" Fill="Orange" VerticalAlignment="Top" >
<Ellipse.Effect>
<BlurEffect Radius="12"/>
</Ellipse.Effect>
</Ellipse>
</Grid>

<Grid x:Name="bdGrid" Margin="12" UseLayoutRounding="True" ClipToBounds="True">
<Ellipse>
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="#4D000000"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="2*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Ellipse Stroke="#464646" StrokeThickness="1" Grid.Column="1" Grid.Row="1"/>
<Ellipse Stroke="#959595" Margin="4" StrokeThickness="6" Grid.Column="1" Grid.Row="1"/>
<Ellipse Stroke="#464646" Margin="14" StrokeThickness="1" Grid.Column="1" Grid.Row="1"/>
</Grid>

<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Path Data="M5,0 5,0 10,120 0,120z" Fill="#0FA9CE" Stretch="Uniform" Margin="0 30 0 0" RenderTransformOrigin="0.5,1" HorizontalAlignment="Center">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="PointRotate"/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>

<Ellipse Width="28" Height="28" Fill="Black">
<Ellipse.Effect>
<DropShadowEffect Color="#0FA9CE" ShadowDepth="0" Direction="0" BlurRadius="16"/>
</Ellipse.Effect>
</Ellipse>

<Border VerticalAlignment="Bottom" BorderBrush="#10ABD1" BorderThickness="2" Margin="0 0 0 12" Background="Black" Padding="4 2" HorizontalAlignment="Center">
<TextBlock Text="{Binding Value,RelativeSource={RelativeSource Mode=TemplatedParent},StringFormat={}{0:f1}}" FontSize="16" Width="46" TextAlignment="Center" Foreground="White"/>
</Border>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="{x:Type ctrl:TheTextBox}" BasedOn="{StaticResource {x:Type TextBox}}"/>

<Style x:Key="DesignTheTextBox" TargetType="{x:Type ctrl:TheTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ctrl:TheTextBox">
<Border BorderBrush="{StaticResource ControlBorderBrush}" BorderThickness="1" Background="{StaticResource ControlBackground}">
<TextBlock Margin="4 0 0 0" Text="{TemplateBinding Text}" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="{x:Type ctrl:NumberBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="input:InputMethod.IsInputMethodEnabled" Value="False"/>
</Style>

<Style x:Key="DesignNumberBox" TargetType="{x:Type ctrl:NumberBox}">
<Setter Property="input:InputMethod.IsInputMethodEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ctrl:NumberBox">
<Border BorderBrush="{StaticResource ControlBorderBrush}" BorderThickness="1" Background="{StaticResource ControlBackground}">
<TextBlock Margin="4 0 0 0" Text="{TemplateBinding Text}" VerticalAlignment="Center" Foreground="BlueViolet"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="{x:Type ctrl:TheSlider}" BasedOn="{StaticResource {x:Type Slider}}">
<Setter Property="Width" Value="140"/>
<Setter Property="Maximum" Value="100"/>
<Setter Property="IsSnapToTickEnabled" Value="True"/>
<Setter Property="Minimum" Value="0"/>
<Setter Property="AutoToolTipPlacement" Value="BottomRight"/>
<Setter Property="SmallChange" Value="0.1"/>
<Setter Property="LargeChange" Value="0.1"/>
</Style>


<Style TargetType="{x:Type ctrl:TheRadioButton}" BasedOn="{StaticResource {x:Type RadioButton}}">
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>

<Style TargetType="{x:Type ctrl:WaveProgressBar}">
<Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" />
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="WaveFill" Value="#36E7AE"/>
<Setter Property="WaveThickness" Value="2"/>
<Setter Property="WaveStroke" Value="#3649E7"/>
<Setter Property="ShowText" Value="True" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ctrl:WaveProgressBar">
<ControlTemplate.Resources>
<Storyboard x:Key="StoryboardOnLoaded" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)" Storyboard.TargetName="PART_Wave">
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="-400"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<StackPanel>
<Border Background="{TemplateBinding Background}">
<Viewbox>
<Border x:Name="PART_Clip" BorderThickness="{TemplateBinding BorderThickness}" ClipToBounds="True"
BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="100" Width="200" Height="200">
<Border.Clip>
<EllipseGeometry RadiusX="100" RadiusY="100" Center="100,100"/>
</Border.Clip>
<Grid>
<Path x:Name="PART_Wave" Stroke="{TemplateBinding WaveStroke}" ClipToBounds="True" StrokeThickness="{TemplateBinding WaveThickness}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="600" Height="250" Fill="{TemplateBinding WaveFill}" Stretch="Fill" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" Margin="0,0,-400,-20">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,1">
<PolyBezierSegment Points="0.5,1 0.5,0 1,0"/>
<PolyBezierSegment Points="1.5,0 1.5,1 2,1"/>
<PolyBezierSegment Points="2.5,1 2.5,0 3,0"/>
<PolyLineSegment Points="3,0 3,10, 0,10 0,1"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<TextBlock Visibility="{Binding ShowText,RelativeSource={RelativeSource TemplatedParent},Converter={x:Static dxmvmm:BoolToVisibilityConverter.Instance}}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}"
Text="{Binding Value,RelativeSource={RelativeSource Mode=TemplatedParent},StringFormat={}{0:f2}%}"/>
</Grid>

</Border>
</Viewbox>
</Border>

</StackPanel>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded" SourceName="PART_Wave">
<BeginStoryboard Name="BeginStoryboardWave" Storyboard="{StaticResource StoryboardOnLoaded}"/>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.Unloaded" SourceName="PART_Wave">
<StopStoryboard BeginStoryboardName="BeginStoryboardWave"/>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>


<Style TargetType="{x:Type ctrl:SwitchButton}">
<Setter Property="Background" Value="#00F4D5"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ctrl:SwitchButton">
<Border CornerRadius="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=ActualHeight,Converter={StaticResource HalfNumber}}"
BorderThickness="1" Background="{StaticResource ControlBackground}" BorderBrush="{TemplateBinding BorderBrush}">
<Grid>
<Ellipse x:Name="ELLIPSE" HorizontalAlignment="Left" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5"
Fill="Gray" Stroke="{StaticResource ControlBorderBrush}" StrokeThickness="1">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="TranslateX" X="2"/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>


<Style TargetType="{x:Type ctrl:KnobButton}">
<Setter Property="Background" Value="#0068F4"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ctrl:KnobButton">
<Grid x:Name="bdGrid" Width="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}">
<Grid Margin="16" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<RotateTransform x:Name="rotatevalue" Angle="00"/>
</Grid.RenderTransform>

<Ellipse Margin="4" Fill="#FFF6F6F6" Stroke="{StaticResource ControlBorderBrush}" >
<Ellipse.Effect>
<DropShadowEffect ShadowDepth="2" BlurRadius="8" Direction="-90" Color="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Background.(SolidColorBrush.Color)}"/>
</Ellipse.Effect>
</Ellipse>
<Ellipse Margin="12" Fill="{TemplateBinding Background}" Width="8" Height="8" VerticalAlignment="Bottom">
</Ellipse>
</Grid>
<TextBlock Text="{Binding Value,RelativeSource={RelativeSource Mode=TemplatedParent}, StringFormat={}{0:F2}}"
VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>-->
<!--#endregion-->
<!--#region 控制集合-->
<Style TargetType="{x:Type ToggleButton}" >
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontFamily" Value="Microsoft YaHei"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="0" CornerRadius="2">
<Border.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FF71E0C6" Offset="0.0" />
<GradientStop Color="#FF43A88D" Offset="0.2" />
<GradientStop Color="#FF5BB07D" Offset="0.0" />
</LinearGradientBrush>
</Border.Background>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" ></ContentPresenter>
</Border>
<ControlTemplate.Triggers>

<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter Property="UIElement.Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="10" Color="#276AB0" Direction="0" Opacity="0.9" RenderingBias="Performance" ShadowDepth="0" />
</Setter.Value>
</Setter>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="0.9" ScaleY="0.9" />
</Setter.Value>
</Setter>
<Setter Property="RenderTransformOrigin" Value=".5,.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="Category">
<TextBlock Text="{Binding}" FontSize="20" Foreground="#4EB9E4" />
</DataTemplate>
<!--#endregion-->
</ResourceDictionary>

+ 50
- 0
BeDesignerSCADA/View/JsEditWindow.xaml Переглянути файл

@@ -0,0 +1,50 @@
<Window x:Class="BeDesignerSCADA.View.JsEditWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BeDesignerSCADA.View"
xmlns:avae="http://icsharpcode.net/sharpdevelop/avalonedit"
mc:Ignorable="d"
Title="编辑脚本" Height="600" Width="920"
Background="White"
BorderBrush="#FFDEDEDE"
BorderThickness="1"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"
WindowStyle="None">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>

<TabControl Margin="4">
<TabItem Header="属性">
<TreeView x:Name="Tree" Margin="0" AllowDrop="False" MouseMove="Tree_MouseMove">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Properties}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</TabItem>
</TabControl>


<avae:TextEditor AllowDrop="True" Margin="4" Drop="txtBox_Drop" BorderThickness="1" BorderBrush="LightGray" x:Name="txtBox" DragOver="txtBox_DragOver" Grid.Column="1" Padding="4" HorizontalScrollBarVisibility="Disabled"
SyntaxHighlighting="JavaScript" ShowLineNumbers="True" FontSize="16" FontFamily="Consolas"/>
</Grid>

<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Width="80" Height="30" Content="取消" x:Name="CancelBtn" Click="CancelBtn_Click" IsCancel="True"/>
<Button Width="80" Height="30" Content="确认" x:Name="ConfirmBtn" Margin="8 0 4 0" Click="ConfirmBtn_Click"/>
</StackPanel>
</Grid>
</Window>

+ 94
- 0
BeDesignerSCADA/View/JsEditWindow.xaml.cs Переглянути файл

@@ -0,0 +1,94 @@
using BeDesignerSCADA.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace BeDesignerSCADA.View
{
/// <summary>
/// JsEditWindow.xaml 的交互逻辑
/// </summary>
public partial class JsEditWindow : Window
{
public JsEditWindow()
{
InitializeComponent();
Owner = Application.Current.MainWindow;
Closing += (s, e) => { e.Cancel = true; Hide(); };
}

public static JsEditWindow Instance { get; } = new JsEditWindow();

public static string ShowEdit(string script, List<FrameworkElement> selectItems)
{
// 获取所有控件的可用属性
var pros = PropertyHelper.GetCustomerControlProperty(selectItems);
Instance.Tree.ItemsSource = pros;
Instance.txtBox.Text = script;
Instance.ShowDialog();

if (Instance.IsOk)
{
return Instance.txtBox.Text;
}
else
{
return script;
}
}

public bool IsOk { get; set; }
private void CancelBtn_Click(object sender, RoutedEventArgs e)
{
IsOk = false;
Close();
}

private void ConfirmBtn_Click(object sender, RoutedEventArgs e)
{
IsOk = true;
Close();
}

private void Tree_MouseMove(object sender, MouseEventArgs e)
{
if (Tree.SelectedItem != null && e.LeftButton == MouseButtonState.Pressed)
{
DragDrop.DoDragDrop(Tree, Tree.SelectedItem, System.Windows.DragDropEffects.Copy);
}
}

private void txtBox_Drop(object sender, DragEventArgs e)
{
e.Effects = DragDropEffects.Copy;
var data = ((ControlName)e.Data.GetData("BeDesignerSCADA.Common.ControlName"));
var str = $"{(data.Parent == null ? string.Empty : (data.Parent.Name + "."))}{data.Name}";

var position = txtBox.GetPositionFromPoint(e.GetPosition(txtBox));
if (position == null)
{
txtBox.Text += str;
return;
}

var offset = txtBox.Document.GetOffset(position.Value.Location);
txtBox.SelectionStart = offset;
txtBox.Document.Insert(offset, str);
}

private void txtBox_DragOver(object sender, DragEventArgs e)
{
e.Effects = DragDropEffects.Copy;
}
}
}

+ 80
- 0
BeDesignerSCADA/ViewModel/EventModel.cs Переглянути файл

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BeDesignerSCADA.ViewModel
{
/// <summary>
/// 事件Model
/// </summary>
public class EventModel
{
/// <summary>
/// 事件id
/// </summary>
public string EventId { get; set; }
/// <summary>
/// 事件名称
/// </summary>
public string EventName { get; set; }
/// <summary>
/// 事件值
/// </summary>
public string EventValue { get; set; }
/// <summary>
/// 特性:分组
/// </summary>
public string Category { get; set; }
/// <summary>
/// 特性:描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 特性:是否启用
/// </summary>
public bool Browsable { get; set; }

public EventModel()
{
EventId=Guid.NewGuid().ToString();
}
}

/// <summary>
/// 数据Model
/// </summary>
public class ALLModel
{
/// <summary>
/// 数据id
/// </summary>
public string DataId { get; set; }
/// <summary>
/// 数据名称
/// </summary>
public string DataName { get; set; }
/// <summary>
/// 数据值
/// </summary>
public string DataValue { get; set; }
/// <summary>
/// 特性:分组
/// </summary>
public string Category { get; set; }
/// <summary>
/// 特性:描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 特性:是否启用
/// </summary>
public bool Browsable { get; set; }

public ALLModel()
{
DataId = Guid.NewGuid().ToString();
}
}
}

+ 871
- 0
BeDesignerSCADA/ViewModel/MainViewModel.cs Переглянути файл

@@ -0,0 +1,871 @@
using BeDesignerSCADA.Common;
using BeDesignerSCADA.Controls;
using BeDesignerSCADA.View;
using BPASmartClient.Compiler;
using BPASmartClient.DATABUS;
using BPASmartClient.MessageName;
using BPASmartClient.MessageName.EnumHelp;
using BPASmartClient.MessageName.发送消息Model;
using BPASmartClient.MessageName.接收消息Model;
using ICSharpCode.AvalonEdit;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;

namespace BeDesignerSCADA.ViewModel
{
/// <summary>
/// 主函数 ViewModel
/// </summary>
public class MainViewModel :ObservableObject
{
public MainViewModel()
{
IsRunning = false;
//启动 或者 停止
RunUiCommand = new RelayCommand(() =>
{
IsRunning = !IsRunning;
});

}

#region 变量
/// <summary>
/// 设置
/// </summary>
public Xceed.Wpf.Toolkit.PropertyGrid.PropertyGrid propertyGrid = null;
/// <summary>
/// 是否正在运行状态
/// </summary>
private bool _IsRunning = false;
public bool IsRunning
{
get
{
return _IsRunning;
}
set
{
_IsRunning = value;
if (value)
{
RunCanvasVisibility = Visibility.Visible;
CanvasPanelVisibility = Visibility.Hidden;
}
else
{
RunCanvasVisibility = Visibility.Hidden;
CanvasPanelVisibility = Visibility.Visible;
}
OnPropertyChanged("IsRunning");
}
}
/// <summary>
/// 画布是否显示
/// </summary>
private Visibility _CanvasPanelVisibility;
public Visibility CanvasPanelVisibility
{
get
{
return _CanvasPanelVisibility;
}
set
{
if (_CanvasPanelVisibility == value)
return;
_CanvasPanelVisibility = value;
OnPropertyChanged("CanvasPanelVisibility");
}
}

/// <summary>
/// 运行代码是否显示
/// </summary>
private Visibility _RunCanvasVisibility;
public Visibility RunCanvasVisibility
{
get
{
return _RunCanvasVisibility;
}
set
{
if (_RunCanvasVisibility == value)
return;
_RunCanvasVisibility = value;
OnPropertyChanged("RunCanvasVisibility");
}
}

/// <summary>
/// 当前代码Xaml
/// </summary>
private string _XamlCode;
public string XamlCode
{
get
{
return _XamlCode;
}
set
{
if (_XamlCode == value)
return;
_XamlCode = value;
OnPropertyChanged("XamlCode");
}
}

/// <summary>
/// 选中控件
/// </summary>
private FrameworkElement _CanSelectedItem;
public FrameworkElement CanSelectedItem
{
get
{
return _CanSelectedItem;
}
set
{
if (_CanSelectedItem == value)
return;
_CanSelectedItem = value;
DataSX();
OnPropertyChanged("CanSelectedItem");
}
}


private PropertyGridCommand _pro;
public PropertyGridCommand PropeObject
{
get
{
return _pro;
}
set
{
_pro = value;
OnPropertyChanged("PropeObject");
}
}

private ObservableCollection<string> _DevNameList;
public ObservableCollection<string> DevNameList
{
get
{
return _DevNameList;
}
set
{
_DevNameList = value;
OnPropertyChanged("DevNameList");
}
}
private ObservableCollection<string> _DevValueList;
public ObservableCollection<string> DevValueList
{
get
{
return _DevValueList;
}
set
{
_DevValueList = value;
OnPropertyChanged("DevValueList");
}
}
#endregion

#region 命令
/// <summary>
/// 启动或者停止
/// </summary>
public RelayCommand RunUiCommand { get; set; }

#endregion

#region 常用函数

/// <summary>
/// 显示当前xaml代码
/// </summary>
public void ShowCode(TextEditor textEditor)
{
textEditor.Text = canvasPanel.Save();
}
#endregion

#region 脚本编辑数据
public CanvasPanel canvasPanel;
/// <summary>
/// 加载
/// </summary>
/// <param name="obj"></param>
public void Loaded(object obj)
{
canvasPanel = obj as CanvasPanel;
}

/// <summary>
/// 编辑
/// </summary>
/// <param name="obj"></param>
public void Edit(object obj)
{
string result = JsEditWindow.ShowEdit(((Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem)obj).Value?.ToString(),canvasPanel.GetAllExecChildren());
((Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem)obj).Value = result;
}
#endregion

#region 图片选择路径
public void SelectPath(object obj)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "图片|*.jpg;*.png;*.gif;*.jpeg;*.bmp";
if (ofd.ShowDialog() == true)
{
//((DevExpress.Xpf.Editors.EditableDataObject)obj).Value = ofd.FileName;
}
}
#endregion

#region 属性填充
Dictionary<string,string> EventName = new Dictionary<string,string> {

{"Name","名称" },
{"Text","文本" },
{"Content","按钮文本" },
{"Title","标题" },
{"Value","变量" },
{"ClickExec","点击事件" },
{"ValueChangedExecute" , "值改变事件"},
{"TikcExecute" , "定时触发"},
{"CheckedExec" , "勾选事件"},
{"UnCheckedExec" , "取消勾选事件"},
{"EventReceiveNameList" , "接收消息集"},

//{"DataSouceType" , "数据来源类型"},
{ "TimeCount" , "定时间隔"},

{ "InterfaceMode" , "接口类型"},
{ "InterfaceParameters" , "接口参数"},

{ "DataSouceInformation" , "连接信息"},

{ "DeviceName" , "设备名称"},
{ "DeviceValuleName" , "设备解析变量"},
{"FDataSouce" , "数据源"},
{ "Code" , "代码过滤脚本"},
{ "GenerateData" , "数据结果"},
};
//{"EventSendNameList" , "发送事件集"}
/// <summary>
/// 数据刷新
/// </summary>
public void DataSX()
{
//if (CanSelectedItem is System.Windows.Controls.Control)
{
//属性变量
PropertyGridCommand cmd = new PropertyGridCommand();
var content = CanSelectedItem;// as System.Windows.Controls.Control;
if (content is IExecutable executable)
executable.PropertyChange += Executable_PropertyChange;

foreach (var item in EventName)
{
System.Reflection.PropertyInfo info = content.GetType().GetProperty(item.Key);
var propName = info?.GetValue(content,null);
if (info != null && item.Key == "Content" ? (propName is string) : true)
{
//var taget = this.GetType().GetMembers().Where(t => t.Name.Equals("BrowsableTrue")).FirstOrDefault();
//var datas= CustomAttributeData.GetCustomAttributes(taget)[0];
//cmd.GetType().GetProperty(item.Value).CustomAttributes.Append(datas);
cmd.GetType().GetProperty(item.Value).SetValue(cmd,propName);
}
}
cmd.PropertyChanged += Cmd_PropertyChanged;
PropeObject = cmd;
}
}

private void Executable_PropertyChange(object? sender,EventArgs e)
{
System.Windows.Controls.Control content = CanSelectedItem as System.Windows.Controls.Control;
System.Reflection.PropertyInfo info = content.GetType().GetProperty("GenerateData");
var propName = info?.GetValue(content,null);
PropeObject.GetType().GetProperty("数据结果").SetValue(PropeObject,propName);
DevNameList = new System.Collections.ObjectModel.ObservableCollection<string>();
DevValueList = new System.Collections.ObjectModel.ObservableCollection<string>();
Class_DataBus.GetInstance().Dic_DeviceData.Keys?.ToList().ForEach(key => { DevNameList.Add(key); });
}

[Browsable(true)]
public void BrowsableTrue() { }
[Browsable(false)]
public void BrowsableFalse() { }

/// <summary>
/// 修改属性后
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Cmd_PropertyChanged(object? sender,PropertyChangedEventArgs e)
{
try
{
string name = e.PropertyName;
foreach (var item in EventName)
{
if (item.Value == name)
{
name = item.Key;
}
}
PropertyGridCommand hotinfo = (PropertyGridCommand)sender;
System.Reflection.PropertyInfo info = hotinfo.GetType().GetProperty(e.PropertyName);
var propName = info?.GetValue(hotinfo,null);
ProGridSetValue(name,propName);
}
catch (Exception ex)
{

}

}

/// <summary>
/// 设置变量
/// </summary>
/// <param name="value"></param>
public void ProGridSetValue(string Name,object value)
{
try
{
// if (CanSelectedItem is System.Windows.Controls.Control)
{
var content = CanSelectedItem;// as System.Windows.Controls.Control;
if (Name == "Content" ? (content is BPASmartClient.SCADAControl.CustomerControls.TheButton) : true)
{
System.Reflection.PropertyInfo info = content.GetType().GetProperty(Name);
info?.SetValue(content,value,null);
}
}
}
catch (Exception ex)
{

}
}
#endregion

#region 设置
/// <summary>
/// 设置Browsable特性的值
/// </summary>
/// <param name="obj"></param>
/// <param name="propertyName"></param>
/// <param name="visible"></param>
public void SetPropertyVisibility(object obj,string propertyName,bool visible)
{
//Type type = typeof(BrowsableAttribute);
//PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
//AttributeCollection attrs = props[propertyName].Attributes;
//type.GetProperty("Browsable").SetValue(attrs[type], visible);

//AttributeCollection attributes =
// TypeDescriptor.GetProperties(obj)[propertyName].Attributes;
//// Checks to see if the property is browsable.
//BrowsableAttribute myAttribute = (BrowsableAttribute)attributes[typeof(
//BrowsableAttribute)];

//if (myAttribute.Browsable)
//{
// // Insert code here.
//}

//PropertyDescriptorCollection appSetingAttributes = TypeDescriptor.GetProperties(obj);
//Type type = typeof(BrowsableAttribute);
//FieldInfo fieldInfo = type.GetField("_displayName", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance);
//fieldInfo.SetValue(appSetingAttributes["TextID"].Attributes[displayType], "修改后的文本ID");

}
/// <summary>
/// 设置Category特性的值
/// </summary>
/// <param name="obj"></param>
/// <param name="propertyName"></param>
/// <param name="str"></param>
public void SetCategoryValue(object obj,string propertyName,string str)
{
Type type = typeof(CategoryAttribute);
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
AttributeCollection attrs = props[propertyName].Attributes;
FieldInfo fld = type.GetField("categoryValue",BindingFlags.Instance | BindingFlags.NonPublic);
fld?.SetValue(attrs[type],str);
}
/// <summary>
/// 获取类的属性成员的Category特性的值
/// </summary>
/// <param name="obj"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
public string GetCategoryValue(object obj,string propertyName)
{
Type type = typeof(CategoryAttribute);
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
AttributeCollection attrs = props[propertyName].Attributes;
FieldInfo fld = type.GetField("categoryValue",BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var str = fld?.GetValue(attrs[type])?.ToString();
return str;

}
/// <summary>
/// 设置类的CategoryOrderAttribute特性的值
/// </summary>
/// <param name="obj"></param>
/// <param name="categoryOrders"></param>
public void SetCategoryOrderValue(object obj,CategoryOrderAttribute[] categoryOrders)
{
TypeDescriptor.AddAttributes(obj.GetType(),categoryOrders);

}
/// <summary>
/// 使用反射设置嵌套属性的值
/// </summary>
/// <param name="obj">对象 </param>
/// <param name="propename">第一层属性</param>
/// <param name="targetname">目标属性(是第一层属性的成员)</param>
/// <param name="val">赋的值</param>
private void NestPropeSetValue(object obj,string propename,string targetname,object val)
{
PropertyInfo[] propertyInfos = obj.GetType().GetProperties();
var prope = propertyInfos.Single(x => propename == x.PropertyType.Name);
var value = prope.GetValue(obj,null);
var pr = value.GetType().GetProperties().Single(x => x.Name == targetname);
pr?.SetValue(value,val);

}
#endregion
}


[CategoryOrder("基本属性",1), CategoryOrder("事件",2)]//分组在排序
public class PropertyGridCommand :ObservableObject
{
private string _名称;
private string _文本;
private string _标题;
private string _文本1;
private object _变量;

[Category("基本属性"), Description("Name"), Browsable(true), PropertyOrder(1)]
public string 名称
{
get
{
return _名称;
}
set
{
if (_名称 == value)
return;
_名称 = value;
OnPropertyChanged("名称");
}
}
[Category("基本属性"), Description("Text"), Browsable(true), PropertyOrder(3)]
public string 文本
{
get
{
return _文本;
}
set
{
if (_文本 == value)
return;
_文本 = value;
OnPropertyChanged("文本");
}
}
[Category("基本属性"), Description("Title"), Browsable(true), PropertyOrder(2)]
public string 标题
{
get
{
return _标题;
}
set
{
if (_标题 == value)
return;
_标题 = value;
OnPropertyChanged("标题");
}
}
[Category("基本属性"), Description("Content"), Browsable(true), PropertyOrder(3)]
public string 按钮文本
{
get
{
return _文本1;
}
set
{
if (_文本1 == value)
return;
_文本1 = value;
OnPropertyChanged("按钮文本");
}
}
[Category("基本属性"), Description("Value"), Browsable(true), PropertyOrder(4)]
public object 变量
{
get
{
return _变量;
}
set
{
if (_变量 == value)
return;
_变量 = value;
OnPropertyChanged("变量");
}
}
//[Category("基本属性"), Description("Content"), Browsable(true), PropertyOrder(2)]
//public string 内容 { get; set; }
//[Category("基本属性"), Description("Header"), Browsable(true), PropertyOrder(3)]
//public string 标题 { get; set; }
//[Category("基本属性"), Description("Text"), Browsable(true), PropertyOrder(4)]
//public object 文本 { get; set; }
//[Category("基本属性"), Description("NumberValue"), Browsable(true), PropertyOrder(5)]
//public object 值 { get; set; }
//[Category("基本属性"), Description("CurValue"), Browsable(true), PropertyOrder(5)]
//public object 数值 { get; set; }
//[Category("基本属性"), Description("StatusValue"), Browsable(true), PropertyOrder(6)]
//public string 状态值 { get; set; }
//[Category("基本属性"), Description("IsChecked"), Browsable(true), PropertyOrder(7)]
//public string 勾选状态 { get; set; }
//[Category("基本属性"), Description("Value"), Browsable(true), PropertyOrder(7)]
//public string 数值1 { get; set; }
//[Category("基本属性"), Description("MaxValue"), Browsable(true), PropertyOrder(8)]
//public string 最大值 { get; set; }
//[Category("基本属性"), Description("MinValue"), Browsable(true), PropertyOrder(9)]
//public object 最小值 { get; set; }
//[Category("基本属性"), Description("Maximum"), Browsable(true), PropertyOrder(8)]
//public string 最大值1 { get; set; }
//[Category("基本属性"), Description("Minimum"), Browsable(true), PropertyOrder(9)]
//public object 最小值1 { get; set; }
//[Category("基本属性"), Description("Interval"), Browsable(true), PropertyOrder(10)]
//public object 间隔 { get; set; }
//[Category("基本属性"), Description("左边距"), Browsable(true), PropertyOrder(11)]
//public string 左边距 { get; set; }
//[Category("基本属性"), Description("上边距"), Browsable(true), PropertyOrder(12)]
//public string 上边距 { get; set; }

//事件处理中心

private string _点击事件;
private string _值改变事件;
private string _定时触发;
private string _勾选事件;
private string _取消勾选事件;

private ObservableCollection<EventReceiveMessage> _接收消息集;

[Category("事件-内部触发"), Description("ClickExec"), Browsable(true), PropertyOrder(1)]
public string 点击事件
{
get
{
return _点击事件;
}
set
{
if (_点击事件 == value)
return;
_点击事件 = value;
OnPropertyChanged("点击事件");
}
}
[Category("事件-内部触发"), Description("ValueChangedExecute"), Browsable(true), PropertyOrder(2)]
public string 值改变事件
{
get
{
return _值改变事件;
}
set
{
if (_值改变事件 == value)
return;
_值改变事件 = value;

OnPropertyChanged("值改变事件");
}
}
[Category("事件-内部触发"), Description("TikcExecute"), Browsable(true), PropertyOrder(3)]
public string 定时触发
{
get
{
return _定时触发;
}
set
{
if (_定时触发 == value)
return;
_定时触发 = value;

OnPropertyChanged("定时触发");
}
}
[Category("事件-内部触发"), Description("CheckedExec"), Browsable(true), PropertyOrder(4)]
public string 勾选事件
{
get
{
return _勾选事件;
}
set
{
if (_勾选事件 == value)
return;
_勾选事件 = value;

OnPropertyChanged("勾选事件");
}
}
[Category("事件-内部触发"), Description("UnCheckedExec"), Browsable(true), PropertyOrder(5)]
public string 取消勾选事件
{
get
{
return _取消勾选事件;
}
set
{
if (_取消勾选事件 == value)
return;
_取消勾选事件 = value;

OnPropertyChanged("取消勾选事件");
}
}

[Category("外部-内部接收消息集"), Description("EventReceiveNameList"), Browsable(true), PropertyOrder(2)]
public ObservableCollection<EventReceiveMessage> 接收消息集
{
get
{
return _接收消息集;
}
set
{
if (_接收消息集 == value)
return;
_接收消息集 = value;
OnPropertyChanged("接收消息集");
}
}




//private DataTypeEnum _数据来源类型;
//[Category("*数据绑定模块*"), Description("DataSouceType"), Browsable(true), PropertyOrder(1)]
//public DataTypeEnum 数据来源类型
//{
// get
// {
// return _数据来源类型;
// }
// set
// {
// if (_数据来源类型 == value)
// return;
// _数据来源类型 = value;
// OnPropertyChanged("数据来源类型");
// }
//}

private string _设备名称;
[Category("*数据绑定模块*"), Description("DeviceName"), Browsable(true), PropertyOrder(2)]
public string 设备名称
{
get
{
return _设备名称;
}
set
{
if (_设备名称 == value)
return;
_设备名称 = value;
OnPropertyChanged("设备名称");
}
}

private string _设备解析变量;
[Category("*数据绑定模块*"), Description("DeviceValuleName"), Browsable(true), PropertyOrder(3)]
public string 设备解析变量
{
get
{
return _设备解析变量;
}
set
{
if (_设备解析变量 == value)
return;
_设备解析变量 = value;
OnPropertyChanged("设备解析变量");
}
}

private InterfaceModeEnum _接口类型;
[Category("*数据绑定模块*"), Description("InterfaceMode"), Browsable(true), PropertyOrder(4)]
public InterfaceModeEnum 接口类型
{
get
{
return _接口类型;
}
set
{
if (_接口类型 == value)
return;
_接口类型 = value;
OnPropertyChanged("接口类型");
}
}


private string _接口参数;
[Category("*数据绑定模块*"), Description("InterfaceParameters"), Browsable(true), PropertyOrder(5)]
public string 接口参数
{
get
{
return _接口参数;
}
set
{
if (_接口参数 == value)
return;
_接口参数 = value;
OnPropertyChanged("接口参数");
}
}

private string _数据来源变量;
[Category("*数据绑定模块*"), Description("DataSouceInformation"), Browsable(true), PropertyOrder(4)]
public string 连接信息
{
get
{
return _数据来源变量;
}
set
{
if (_数据来源变量 == value)
return;
_数据来源变量 = value;
OnPropertyChanged("连接信息");
}
}

private string _数据源;
[Category("*数据绑定模块*"), Description("FDataSouce"), Browsable(true), PropertyOrder(5)]
public string 数据源
{
get
{
return _数据源;
}
set
{
if (_数据源 == value)
return;
_数据源 = value;
OnPropertyChanged("数据源");
}
}

private string _代码过滤脚本;
[Category("*数据绑定模块*"), Description("Code"), Browsable(true), PropertyOrder(6)]
public string 代码过滤脚本
{
get
{
return _代码过滤脚本;
}
set
{
if (_代码过滤脚本 == value)
return;
_代码过滤脚本 = value;
OnPropertyChanged("代码过滤脚本");
}
}

private string _数据结果;
[Category("*数据绑定模块*"), Description("GenerateData"), Browsable(true), PropertyOrder(7)]
public string 数据结果
{
get
{
return _数据结果;
}
set
{
if (_数据结果 == value)
return;
_数据结果 = value;
OnPropertyChanged("数据结果");
}
}

private int _定时调用;
[Category("*数据绑定模块*"), Description("TimeCount"), Browsable(true), PropertyOrder(100)]
public int 定时间隔
{
get
{
return _定时调用;
}
set
{
if (_定时调用 == value)
return;
_定时调用 = value;
OnPropertyChanged("定时间隔");
}
}



}


}

+ 27
- 1
SmartClient.sln Переглянути файл

@@ -170,7 +170,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputerTestDemo", "Compute
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "5.加载UI程序", "5.加载UI程序", "{1DA0F827-5F3D-4B87-9B51-6C0BF5365A3F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BPASmartClient.MinimalistUI", "BPASmartClient.MinimalistUI\BPASmartClient.MinimalistUI.csproj", "{AE49009F-B7D9-482E-AD1F-4514435272E1}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.MinimalistUI", "BPASmartClient.MinimalistUI\BPASmartClient.MinimalistUI.csproj", "{AE49009F-B7D9-482E-AD1F-4514435272E1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "6.配置工具", "6.配置工具", "{06F0B369-0483-46DD-82D2-70431FB505C1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeDesignerSCADA", "BeDesignerSCADA\BeDesignerSCADA.csproj", "{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1566,6 +1570,26 @@ Global
{AE49009F-B7D9-482E-AD1F-4514435272E1}.Release|x64.Build.0 = Release|Any CPU
{AE49009F-B7D9-482E-AD1F-4514435272E1}.Release|x86.ActiveCfg = Release|Any CPU
{AE49009F-B7D9-482E-AD1F-4514435272E1}.Release|x86.Build.0 = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|ARM.ActiveCfg = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|ARM.Build.0 = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|ARM64.Build.0 = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|x64.ActiveCfg = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|x64.Build.0 = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|x86.ActiveCfg = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Debug|x86.Build.0 = Debug|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|Any CPU.Build.0 = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|ARM.ActiveCfg = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|ARM.Build.0 = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|ARM64.ActiveCfg = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|ARM64.Build.0 = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|x64.ActiveCfg = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|x64.Build.0 = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|x86.ActiveCfg = Release|Any CPU
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1645,6 +1669,8 @@ Global
{8940F1E2-693D-407E-AD03-722718860609} = {CDC1E762-5E1D-4AE1-9DF2-B85761539086}
{1DA0F827-5F3D-4B87-9B51-6C0BF5365A3F} = {7B0175AD-BB74-4A98-B9A7-1E289032485E}
{AE49009F-B7D9-482E-AD1F-4514435272E1} = {1DA0F827-5F3D-4B87-9B51-6C0BF5365A3F}
{06F0B369-0483-46DD-82D2-70431FB505C1} = {7B0175AD-BB74-4A98-B9A7-1E289032485E}
{DF8B4C38-39DE-4220-AB60-885CAE6D1E47} = {06F0B369-0483-46DD-82D2-70431FB505C1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9AEC9B81-0222-4DE9-B642-D915C29222AC}


Завантаження…
Відмінити
Зберегти