Sfoglia il codice sorgente

增加配置工具

样式分支
fyf 2 anni fa
parent
commit
189d317eae
71 ha cambiato i file con 6513 aggiunte e 1 eliminazioni
  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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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;
}
}

BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


+ 76
- 0
BeDesignerSCADA/Helper/Config.cs Vedi File

@@ -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;
});
}
}
}

BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


BIN
Vedi File


+ 296
- 0
BeDesignerSCADA/MainWindow.xaml Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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}


Caricamento…
Annulla
Salva