@@ -0,0 +1,14 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<TargetFramework>net6.0</TargetFramework> | |||||
<ImplicitUsings>enable</ImplicitUsings> | |||||
<Nullable>enable</Nullable> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<ProjectReference Include="..\BPASmartClient.Helper\BPASmartClient.Helper.csproj" /> | |||||
<ProjectReference Include="..\BPASmartClinet.DataBusName\BPASmartClinet.DataBusName.csproj" /> | |||||
</ItemGroup> | |||||
</Project> |
@@ -0,0 +1,236 @@ | |||||
| |||||
using BPASmartClient.Bus.DataBus; | |||||
using BPASmartClient.Helper; | |||||
using BPASmartClinet.DataBusName; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
/* *********************************************** | |||||
* subject 数据总线,总线入口,后续按类型分发 | |||||
* author 张原川 | |||||
* date 2019/6/3 9:49:03 | |||||
* ***********************************************/ | |||||
namespace LandStation.Bus.DataBus | |||||
{ | |||||
public class DataBus : Singleton<DataBus>, IDisposable | |||||
{ | |||||
//原始数据总线 | |||||
private IDataBus<byte> _dataBus_rawdata; | |||||
//MAVLINK消息总线 | |||||
private IDataBus<object> _dataBus_mavMessage; | |||||
//参数总线 | |||||
private IDataBus<object> _dataBus_parameter; | |||||
//调试消息总线 | |||||
private IDataBus<string> _dataBus_message; | |||||
/// <summary> | |||||
/// 数据总线初始化 | |||||
/// </summary> | |||||
public void Initialize() | |||||
{ | |||||
_dataBus_rawdata = new DataBus_Byte(); | |||||
_dataBus_mavMessage = new DataBus_Currency<object>(); | |||||
_dataBus_parameter = new DataBus_Currency<object>(); | |||||
_dataBus_message = new DataBus_Currency<string>(); | |||||
} | |||||
/// <summary> | |||||
/// 总线开启 | |||||
/// </summary> | |||||
public void Start() | |||||
{ | |||||
Executer.GetInstance().Start(_dataBus_rawdata.StartBus, ActionKey.DataBus_Rawdata); | |||||
Executer.GetInstance().Start(_dataBus_mavMessage.StartBus, ActionKey.DataBus_MAVLinkMessage); | |||||
Executer.GetInstance().Start(_dataBus_message.StartBus, ActionKey.DataBus_MessageData); | |||||
Executer.GetInstance().Start(_dataBus_parameter.StartBus, ActionKey.DataBus_ParameterData); | |||||
//Executer.GetInstance().Start(delegate () | |||||
//{ | |||||
// while (true) | |||||
// { | |||||
// //Console.WriteLine("原始数据========>批量数据订阅数:{0},单数据订阅数:{1}", _dataBus_rawdata.MultSubscriberCount, _dataBus_rawdata.SingleSubscriberCount); | |||||
// //Console.WriteLine("MAVLink数据=====>批量数据订阅数:{0},单数据订阅数:{1}", _dataBus_mavMessage.MultSubscriberCount, _dataBus_mavMessage.SingleSubscriberCount); | |||||
// //Console.WriteLine("状态数据========>批量数据订阅数:{0},单数据订阅数:{1}", _dataBus_status.MultSubscriberCount, _dataBus_status.SingleSubscriberCount); | |||||
// //Console.WriteLine("参数数据========>批量数据订阅数:{0},单数据订阅数:{1}", _dataBus_parameter.MultSubscriberCount, _dataBus_parameter.SingleSubscriberCount); | |||||
// //Console.WriteLine("消息数据========>批量数据订阅数:{0},单数据订阅数:{1}", _dataBus_message.MultSubscriberCount, _dataBus_message.SingleSubscriberCount); | |||||
// //Console.WriteLine("==============================================================================================="); | |||||
// Console.WriteLine("原始数据========>{0}", _dataBus_rawdata.DataCount); | |||||
// Console.WriteLine("MAVLink数据=====>{0}", _dataBus_mavMessage.DataCount); | |||||
// Console.WriteLine("状态数据========>{0}", _dataBus_status.DataCount); | |||||
// Console.WriteLine("参数数据========>{0}", _dataBus_parameter.DataCount); | |||||
// Console.WriteLine("消息数据========>{0}", _dataBus_message.DataCount); | |||||
// Console.WriteLine("==============================================================================================="); | |||||
// Thread.Sleep(50); | |||||
// } | |||||
//}, ActionKey.DataBus_Monitor, "数据总线监控"); | |||||
} | |||||
/// <summary> | |||||
/// 根据数据类型放入数据到对应总线 | |||||
/// </summary> | |||||
/// <typeparam name="TData">数据实际类型</typeparam> | |||||
/// <param name="data">数据</param> | |||||
/// <param name="simpleData">数据业务类型</param> | |||||
public void Put<TData>(object data, SimpleDataType simpleData) | |||||
{ | |||||
switch (simpleData) | |||||
{ | |||||
case SimpleDataType.RAW_DATA: | |||||
if (data is byte) | |||||
_dataBus_rawdata.Put((byte)data); | |||||
if (data is byte[]) | |||||
_dataBus_rawdata.Put((byte[])data); | |||||
break; | |||||
case SimpleDataType.MAV_MESSAGE_DATA: | |||||
_dataBus_mavMessage.Put((object)data); | |||||
break; | |||||
case SimpleDataType.PARAMETER: | |||||
_dataBus_parameter.Put((object)data); | |||||
break; | |||||
case SimpleDataType.MESSAGE_DATA: | |||||
_dataBus_message.Put((string)data); | |||||
break; | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// 订阅数据 | |||||
/// </summary> | |||||
/// <typeparam name="TData">数据实际类型</typeparam> | |||||
/// <param name="action">接收数据推送回调</param> | |||||
/// <param name="dataType">数据业务类型</param> | |||||
public void Subscribe<TData>(Action<TData> action, SimpleDataType dataType) | |||||
{ | |||||
switch (dataType) | |||||
{ | |||||
case SimpleDataType.RAW_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_rawdata).Subscribe(action); | |||||
break; | |||||
case SimpleDataType.MAV_MESSAGE_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_mavMessage).Subscribe(action); | |||||
break; | |||||
case SimpleDataType.PARAMETER: | |||||
((ISimpleDataBus<TData>)_dataBus_parameter).Subscribe(action); | |||||
break; | |||||
case SimpleDataType.MESSAGE_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_message).Subscribe(action); | |||||
break; | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// 订阅数据 | |||||
/// </summary> | |||||
/// <typeparam name="TData">数据实际类型</typeparam> | |||||
/// <param name="action">接收数据推送回调</param> | |||||
/// <param name="dataType">数据业务类型</param> | |||||
public void UnSubscribe<TData>(Action<TData> action, SimpleDataType dataType) | |||||
{ | |||||
switch (dataType) | |||||
{ | |||||
case SimpleDataType.RAW_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_rawdata).UnSubcribe(action); | |||||
break; | |||||
case SimpleDataType.MAV_MESSAGE_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_mavMessage).UnSubcribe(action); | |||||
break; | |||||
case SimpleDataType.PARAMETER: | |||||
((ISimpleDataBus<TData>)_dataBus_parameter).UnSubcribe(action); | |||||
break; | |||||
case SimpleDataType.MESSAGE_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_message).UnSubcribe(action); | |||||
break; | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// 订阅数据 | |||||
/// </summary> | |||||
/// <typeparam name="TData">数据实际类型</typeparam> | |||||
/// <param name="action">接收数据推送回调</param> | |||||
/// <param name="dataType">数据业务类型</param> | |||||
public void Subscribe<TData>(Action<TData[]> action, SimpleDataType dataType) | |||||
{ | |||||
switch (dataType) | |||||
{ | |||||
case SimpleDataType.RAW_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_rawdata).Subscribe(action); | |||||
break; | |||||
case SimpleDataType.MAV_MESSAGE_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_mavMessage).Subscribe(action); | |||||
break; | |||||
case SimpleDataType.PARAMETER: | |||||
((ISimpleDataBus<TData>)_dataBus_parameter).Subscribe(action); | |||||
break; | |||||
case SimpleDataType.MESSAGE_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_message).Subscribe(action); | |||||
break; | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// 订阅数据 | |||||
/// </summary> | |||||
/// <typeparam name="TData">数据实际类型</typeparam> | |||||
/// <param name="action">接收数据推送回调</param> | |||||
/// <param name="dataType">数据业务类型</param> | |||||
public void UnSubscribe<TData>(Action<TData[]> action, SimpleDataType dataType) | |||||
{ | |||||
switch (dataType) | |||||
{ | |||||
case SimpleDataType.RAW_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_rawdata).UnSubcribe(action); | |||||
break; | |||||
case SimpleDataType.MAV_MESSAGE_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_mavMessage).UnSubcribe(action); | |||||
break; | |||||
case SimpleDataType.PARAMETER: | |||||
((ISimpleDataBus<TData>)_dataBus_parameter).UnSubcribe(action); | |||||
break; | |||||
case SimpleDataType.MESSAGE_DATA: | |||||
((ISimpleDataBus<TData>)_dataBus_message).UnSubcribe(action); | |||||
break; | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// 获取一个数据 | |||||
/// </summary> | |||||
/// <typeparam name="TData">数据实际类型</typeparam> | |||||
/// <param name="dataType">数据业务类型</param> | |||||
/// <returns>一个数据</returns> | |||||
public byte GetRawdata() | |||||
{ | |||||
return ((IGivenDataBus<byte>)_dataBus_rawdata).Get(); | |||||
} | |||||
/// <summary> | |||||
/// 获取多个数据 | |||||
/// </summary> | |||||
/// <typeparam name="TData">数据实际类型</typeparam> | |||||
/// <param name="dataType">数据业务类型</param> | |||||
/// <param name="length">获取数据长度</param> | |||||
/// <returns>一个数据</returns> | |||||
public byte[] GetRawdata(int length) | |||||
{ | |||||
return ((IGivenDataBus<byte>)_dataBus_rawdata).Get(length); | |||||
} | |||||
/// <summary> | |||||
/// 释放数据总线 | |||||
/// </summary> | |||||
public void Dispose() | |||||
{ | |||||
_dataBus_rawdata.StopBus(); | |||||
_dataBus_mavMessage.StopBus(); | |||||
_dataBus_message.StopBus(); | |||||
_dataBus_parameter.StopBus(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,98 @@ | |||||
| |||||
using System; | |||||
using System.Collections.Concurrent; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
/* *********************************************** | |||||
* subject Byte类型数据总线,在订阅推送模式基础上 | |||||
* 增加主动获取 | |||||
* author 张原川 | |||||
* date 2019/6/3 14:44:36 | |||||
* ***********************************************/ | |||||
namespace BPASmartClient.Bus.DataBus | |||||
{ | |||||
public class DataBus_Byte : DataBus_Currency<byte>, IGivenDataBus<byte> | |||||
{ | |||||
//接收数据缓冲(用以Get) | |||||
//protected CircularBuffer<byte> _givenDataPool = new CircularBuffer<byte>(1 * 1024 * 1024); | |||||
protected ConcurrentQueue<byte> _givenDataPool = new ConcurrentQueue<byte>(); | |||||
public new int DataCount { get { return _givenDataPool.Count; } } | |||||
/// <summary> | |||||
/// 重写Put方法,加入givenDataPool | |||||
/// </summary> | |||||
public new void Put(byte data) | |||||
{ | |||||
if (!_running) | |||||
return; | |||||
if (_multDataHandlers.Count > 0 || _singleDataHandlers.Count > 0) | |||||
_dataPool.Enqueue(data); | |||||
_givenDataPool.Enqueue(data); | |||||
} | |||||
/// <summary> | |||||
/// 重写Put方法,加入givenDataPool | |||||
/// </summary> | |||||
public new void Put(byte[] data) | |||||
{ | |||||
if (!_running) | |||||
return; | |||||
if (_multDataHandlers.Count > 0 || _singleDataHandlers.Count > 0) | |||||
foreach (var item in data) | |||||
_dataPool.Enqueue(item); | |||||
foreach (var item in data) | |||||
_givenDataPool.Enqueue(item); | |||||
} | |||||
/// <summary> | |||||
/// 数据取出 | |||||
/// </summary> | |||||
public byte Get() | |||||
{ | |||||
agin: | |||||
if (_givenDataPool.Count <= 0) | |||||
{ | |||||
Thread.Sleep(5); | |||||
goto agin; | |||||
} | |||||
byte res; | |||||
while (!_givenDataPool.TryDequeue(out res)) ; | |||||
return res; | |||||
} | |||||
/// <summary> | |||||
/// 数据取出 | |||||
/// </summary> | |||||
public byte[] Get(int count) | |||||
{ | |||||
agin: | |||||
if (_givenDataPool.Count < count) | |||||
{ | |||||
Thread.Sleep(5); | |||||
goto agin; | |||||
} | |||||
//Console.WriteLine(_givenDataPool.Size + "===========" + _dataPool.Size); | |||||
//for (int i = 0; i < count; i++) { | |||||
// _givenDataPool.TryDequeue | |||||
//} | |||||
int i = 0; | |||||
byte[] result = new byte[count]; | |||||
while (i < count) | |||||
{ | |||||
if (_givenDataPool.TryDequeue(out result[i])) | |||||
{ | |||||
i++; | |||||
} | |||||
} | |||||
return result;// _givenDataPool.Get(count); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,190 @@ | |||||
| |||||
using System; | |||||
using System.Collections.Concurrent; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
/* *********************************************** | |||||
* subject 通用数据总线,采取订阅推送模式 | |||||
* author 张原川 | |||||
* date 2019/6/3 15:03:10 | |||||
* ***********************************************/ | |||||
namespace BPASmartClient.Bus.DataBus | |||||
{ | |||||
public class DataBus_Currency<TData> : ISimpleDataBus<TData> | |||||
{ | |||||
//接收数据缓冲 | |||||
//protected CircularBuffer<TData> _dataPool = new CircularBuffer<TData>(1 * 1024 * 1024); | |||||
protected ConcurrentQueue<TData> _dataPool = new ConcurrentQueue<TData>(); | |||||
//订阅数据回调集合 | |||||
protected List<Action<TData[]>> _multDataHandlers = new List<Action<TData[]>>(); | |||||
protected List<Action<TData>> _singleDataHandlers = new List<Action<TData>>(); | |||||
//订阅与推送数据信号量 | |||||
protected AutoResetEvent _are = new AutoResetEvent(false); | |||||
//运行标识 | |||||
protected bool _running = false; | |||||
public int MultSubscriberCount { get { return _multDataHandlers.Count; } } | |||||
public int SingleSubscriberCount { get { return _singleDataHandlers.Count; } } | |||||
public int DataCount { get { return _dataPool.Count; } } | |||||
/// <summary> | |||||
/// 终止事件总线 | |||||
/// </summary> | |||||
public void Dispose() | |||||
{ | |||||
StopBus(); | |||||
} | |||||
/// <summary> | |||||
/// 数据存入 | |||||
/// </summary> | |||||
public void Put(TData data) | |||||
{ | |||||
if (!_running) | |||||
return; | |||||
if (_multDataHandlers.Count > 0 || _singleDataHandlers.Count > 0) | |||||
_dataPool.Enqueue(data); | |||||
} | |||||
/// <summary> | |||||
/// 数据存入 | |||||
/// </summary> | |||||
public void Put(TData[] data) | |||||
{ | |||||
if (!_running) | |||||
return; | |||||
if (_multDataHandlers.Count > 0 || _singleDataHandlers.Count > 0) | |||||
foreach (var item in data) | |||||
_dataPool.Enqueue(item); | |||||
} | |||||
/// <summary> | |||||
/// 开启总线 | |||||
/// </summary> | |||||
public void StartBus() | |||||
{ | |||||
_running = true; | |||||
List<TData> items = new List<TData>(); | |||||
_are.Set(); | |||||
while (_running) | |||||
{ | |||||
int count = _dataPool.Count; | |||||
items.Clear(); | |||||
if (_singleDataHandlers.Count > 0) | |||||
{ | |||||
_are.WaitOne(TimeSpan.FromMilliseconds(10)); | |||||
for (int i = 0; i < count; i++) | |||||
{ | |||||
TData data = default(TData); | |||||
while (!_dataPool.TryDequeue(out data)) ; | |||||
uint msgId = Convert.ToUInt32(data.GetType().GetProperty("msgid").GetValue(data)); | |||||
if (msgId == 316) | |||||
{ | |||||
} | |||||
//var item = _dataPool.Get(); | |||||
//Parallel.ForEach(_singleDataHandlers, p => p.Invoke(items[items.Count - 1])); | |||||
for (int j = 0; j < _singleDataHandlers.Count; j++) | |||||
{ | |||||
_singleDataHandlers[j].Invoke(data); | |||||
} | |||||
items.Add(data); | |||||
} | |||||
} | |||||
if (_multDataHandlers.Count > 0) | |||||
{ | |||||
if (items.Count <= 0) | |||||
{ | |||||
TData data = default(TData); | |||||
for (int i = 0; i < count; i++) | |||||
{ | |||||
while (!_dataPool.TryDequeue(out data)) ; | |||||
items.Add(data); | |||||
} | |||||
//items.AddRange(_dataPool.Get(count)); | |||||
} | |||||
_are.WaitOne(TimeSpan.FromMilliseconds(10)); | |||||
//Parallel.For(0, _multDataHandlers.Count, (i) => | |||||
//{ | |||||
// _multDataHandlers[i].Invoke(items.ToArray()); | |||||
//}); | |||||
for (int i = _multDataHandlers.Count - 1; i >= 0; i--) | |||||
{ | |||||
_multDataHandlers[i].Invoke(items.ToArray()); | |||||
} | |||||
} | |||||
Thread.Sleep(10); | |||||
_are.Set(); | |||||
} | |||||
} | |||||
public void StopBus() | |||||
{ | |||||
_running = false; | |||||
} | |||||
/// <summary> | |||||
/// 数据订阅 | |||||
/// </summary> | |||||
/// <param name="action">接收数据回调</param> | |||||
public void Subscribe(Action<TData> action) | |||||
{ | |||||
if (_singleDataHandlers.Contains(action)) | |||||
return; | |||||
_are.Reset(); | |||||
_singleDataHandlers.Add(action); | |||||
_are.Set(); | |||||
} | |||||
/// <summary> | |||||
/// 数据订阅 | |||||
/// </summary> | |||||
/// <param name="action">接收数据回调</param> | |||||
public void Subscribe(Action<TData[]> action) | |||||
{ | |||||
if (_multDataHandlers.Contains(action)) | |||||
return; | |||||
_are.Reset(); | |||||
_multDataHandlers.Add(action); | |||||
_are.Set(); | |||||
} | |||||
/// <summary> | |||||
/// 取消数据订阅 | |||||
/// </summary> | |||||
/// <param name="action">接收数据回调</param> | |||||
public void UnSubcribe(Action<TData> action) | |||||
{ | |||||
if (!_singleDataHandlers.Contains(action)) | |||||
return; | |||||
_are.Reset(); | |||||
_singleDataHandlers.Remove(action); | |||||
_are.Set(); | |||||
} | |||||
/// <summary> | |||||
/// 取消数据订阅 | |||||
/// </summary> | |||||
/// <param name="action">接收数据回调</param> | |||||
public void UnSubcribe(Action<TData[]> action) | |||||
{ | |||||
if (!_multDataHandlers.Contains(action)) | |||||
return; | |||||
_are.Reset(); | |||||
_multDataHandlers.Remove(action); | |||||
_are.Set(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,149 @@ | |||||
using BPASmartClient.Helper; | |||||
using System; | |||||
using System.Collections.Concurrent; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace BPASmartClient.Bus.DataBus | |||||
{ | |||||
/// <summary> | |||||
/// 线程集中处理委托 | |||||
/// </summary> | |||||
/// <param name="action"></param> | |||||
public delegate void ActionKeyHandle(string action); | |||||
public delegate void ThreadExceptionHandle(string action, Exception ex); | |||||
public delegate void ThreadExitHandle(string action); | |||||
/// <summary> | |||||
/// 执行器 | |||||
/// </summary> | |||||
public class Executer : Singleton<Executer> | |||||
{ | |||||
private System.Timers.Timer _timer4Monitor = new System.Timers.Timer(1000); | |||||
private ConcurrentDictionary<string, Thread> _actions = new ConcurrentDictionary<string, Thread>(); | |||||
private object _async = new object(); | |||||
public event ThreadExceptionHandle OnThreadException; | |||||
public event ThreadExitHandle ThreadExit; | |||||
/// <summary> | |||||
/// 构造器 | |||||
/// </summary> | |||||
public Executer() | |||||
{ | |||||
} | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public void Dispose() | |||||
{ | |||||
_timer4Monitor.Stop(); | |||||
foreach (var th in _actions) | |||||
{ | |||||
try { th.Value.Abort(); } | |||||
catch (ThreadAbortException) { } | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
public List<Thread> GetActionInfos() | |||||
{ | |||||
Monitor.TryEnter(_async, 200); | |||||
var actionInfos = _actions.Values.ToList(); | |||||
Monitor.Exit(_async); | |||||
return actionInfos; | |||||
} | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="key"></param> | |||||
public void Abort(string key) | |||||
{ | |||||
Monitor.TryEnter(_async, 200); | |||||
if (_actions.ContainsKey(key)) | |||||
{ | |||||
try { _actions[key].Abort(); } | |||||
catch (ThreadAbortException) { } | |||||
} | |||||
Monitor.Exit(_async); | |||||
} | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="key"></param> | |||||
/// <returns></returns> | |||||
public bool ContainsKey(string key) | |||||
{ | |||||
Monitor.TryEnter(_async, 200); | |||||
var item = _actions[key]; | |||||
Monitor.Exit(_async); | |||||
if (null != item) | |||||
{ | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="action"></param> | |||||
/// <param name="name"></param> | |||||
/// <param name="isBackground"></param> | |||||
/// <param name="priority"></param> | |||||
public void Start(Action action, string name, bool isBackground = false, ThreadPriority priority = ThreadPriority.Normal) | |||||
{ | |||||
Thread thread = new Thread(() => | |||||
{ | |||||
try | |||||
{ | |||||
action(); | |||||
ThreadExit?.Invoke(name); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
OnThreadException?.Invoke(name, ex); | |||||
} | |||||
}); | |||||
thread.IsBackground = isBackground; | |||||
thread.Priority = priority; | |||||
thread.Name = name; | |||||
thread.Start(); | |||||
Monitor.TryEnter(_async, 50); | |||||
if (_actions.ContainsKey(name)) | |||||
{ | |||||
try { _actions[name].Abort(); } | |||||
catch (ThreadAbortException) { } | |||||
} | |||||
_actions[name] = thread; | |||||
Monitor.Exit(_async); | |||||
} | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="action"></param> | |||||
/// <param name="timeout"></param> | |||||
/// <returns></returns> | |||||
public bool StartWhiteReturn(Func<bool> action, int timeout = 3) | |||||
{ | |||||
DateTime beginTime = DateTime.Now; | |||||
bool doResult = false; | |||||
while (DateTime.Now.Subtract(beginTime).TotalSeconds <= 3 && !doResult) | |||||
{ | |||||
doResult = action(); | |||||
} | |||||
return doResult; | |||||
} | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public event ActionKeyHandle ActionAbort; | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public event ActionKeyHandle ActionStarted; | |||||
} | |||||
} |
@@ -0,0 +1,54 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
/* *********************************************** | |||||
* subject 数据总线接口 | |||||
* author 张原川 | |||||
* date 2019/6/3 11:33:57 | |||||
* ***********************************************/ | |||||
namespace BPASmartClient.Bus.DataBus | |||||
{ | |||||
/// <summary> | |||||
/// 数据总线接口 | |||||
/// </summary> | |||||
public interface IDataBus<TData> | |||||
{ | |||||
/// <summary> | |||||
/// 多数据订阅数量 | |||||
/// </summary> | |||||
int MultSubscriberCount { get; } | |||||
/// <summary> | |||||
/// 单数据订阅数量 | |||||
/// </summary> | |||||
int SingleSubscriberCount { get; } | |||||
/// <summary> | |||||
/// 数据量 | |||||
/// </summary> | |||||
int DataCount { get; } | |||||
/// <summary> | |||||
/// 开启总线 | |||||
/// </summary> | |||||
void StartBus(); | |||||
/// <summary> | |||||
/// 关闭总线 | |||||
/// </summary> | |||||
void StopBus(); | |||||
/// <summary> | |||||
/// 数据放入总线 | |||||
/// </summary> | |||||
/// <param name="data">数据</param> | |||||
void Put(TData data); | |||||
/// <summary> | |||||
/// 数据放入总线 | |||||
/// </summary> | |||||
/// <param name="data">数据</param> | |||||
void Put(TData[] data); | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
/* *********************************************** | |||||
* subject 数据总线接口,定义主动取得数据 | |||||
* author 张原川 | |||||
* date 2019/6/3 11:25:11 | |||||
* ***********************************************/ | |||||
namespace BPASmartClient.Bus.DataBus | |||||
{ | |||||
public interface IGivenDataBus<TData>: IDataBus<TData> | |||||
{ | |||||
/// <summary> | |||||
/// 数据取出 | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
TData Get(); | |||||
/// <summary> | |||||
/// 数据取出 | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
TData[] Get(int count); | |||||
} | |||||
} |
@@ -0,0 +1,33 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
/* *********************************************** | |||||
* subject 数据总线接口,定义原始数据、MAVLINK消息、状态数据、消息数据标准 | |||||
* author 张原川 | |||||
* date 2019/6/3 9:50:01 | |||||
* ***********************************************/ | |||||
namespace BPASmartClient.Bus.DataBus | |||||
{ | |||||
interface ISimpleDataBus<TData>: IDataBus<TData>,IDisposable | |||||
{ | |||||
/// <summary> | |||||
/// 订阅总线数据 | |||||
/// </summary> | |||||
/// <param name="action">数据类型</param> | |||||
void Subscribe(Action<TData> action); | |||||
void Subscribe(Action<TData[]> action); | |||||
/// <summary> | |||||
/// 取消订阅数据 | |||||
/// </summary> | |||||
/// <param name="action">数据类型</param> | |||||
void UnSubcribe(Action<TData> action); | |||||
void UnSubcribe(Action<TData[]> action); | |||||
} | |||||
} |
@@ -0,0 +1,32 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace BPASmartClient.Bus.DataBus | |||||
{ | |||||
public enum SimpleDataType | |||||
{ | |||||
/// <summary> | |||||
/// 原始数据总线 | |||||
/// </summary> | |||||
RAW_DATA, | |||||
/// <summary> | |||||
/// MAVLINK消息总线 | |||||
/// </summary> | |||||
MAV_MESSAGE_DATA, | |||||
/// <summary> | |||||
/// 全局状态数据总线 | |||||
/// </summary> | |||||
STATUS_DATA, | |||||
/// <summary> | |||||
/// 参数总线 | |||||
/// </summary> | |||||
PARAMETER, | |||||
/// <summary> | |||||
/// 调试消息总线 | |||||
/// </summary> | |||||
MESSAGE_DATA | |||||
} | |||||
} |
@@ -0,0 +1,108 @@ | |||||
| |||||
using BPASmartClient.Bus.EventBus; | |||||
using BPASmartClient.Helper; | |||||
using System; | |||||
using System.Collections.Concurrent; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
/* *********************************************** | |||||
* subject 事件总线,总线入口,后续按类型分发 | |||||
* author 张原川 | |||||
* date 2019/6/3 15:49:03 | |||||
* ***********************************************/ | |||||
namespace LandStation.Bus | |||||
{ | |||||
public class EventBus : Singleton<EventBus> | |||||
{ | |||||
//事件处理委托 | |||||
public delegate void EventCallBackHandle(params object[] args); | |||||
//事件处理委托 | |||||
public delegate void EventHandle(IEvent @event, EventCallBackHandle callBack = null); | |||||
//事件订阅者集合 | |||||
private ConcurrentDictionary<Type, List<EventHandle>> _eventHandls = new ConcurrentDictionary<Type, List<EventHandle>>(); | |||||
/// <summary> | |||||
/// 事件订阅 | |||||
/// </summary> | |||||
public void Subscribe<TEvent>(EventHandle handle) | |||||
{ | |||||
if (!_eventHandls.ContainsKey(typeof(TEvent))) | |||||
_eventHandls.TryAdd(typeof(TEvent), new List<EventHandle>()); | |||||
lock (_eventHandls) | |||||
_eventHandls[typeof(TEvent)].Add(handle); | |||||
} | |||||
/// <summary> | |||||
/// 事件退订 | |||||
/// </summary> | |||||
public void UnSubscribe<TEvent>(EventHandle handle) | |||||
{ | |||||
if (_eventHandls.ContainsKey(typeof(TEvent))) | |||||
{ | |||||
if (_eventHandls[typeof(TEvent)].Contains(handle)) | |||||
{ | |||||
lock (_eventHandls) | |||||
_eventHandls[typeof(TEvent)].Remove(handle); | |||||
} | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// 事件发布,不带返回 | |||||
/// </summary> | |||||
public void Publish<TEvent>(TEvent @event) where TEvent : IEvent | |||||
{ | |||||
if (_eventHandls.ContainsKey(typeof(TEvent))) | |||||
{ | |||||
for (int i = _eventHandls[typeof(TEvent)].Count - 1; i >= 0; i--) | |||||
_eventHandls[typeof(TEvent)][i](@event); | |||||
//_eventHandls[typeof(TEvent)].ForEach(p => | |||||
//{ | |||||
// p(@event); | |||||
//}); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// 事件发布,带返回 | |||||
/// </summary> | |||||
public void Publish<TEvent>(TEvent @event, EventCallBackHandle eventCallBack) where TEvent : IEvent | |||||
{ | |||||
List<object> result = new List<object>(); | |||||
if (_eventHandls.ContainsKey(typeof(TEvent))) | |||||
{ | |||||
//_eventHandls[typeof(TEvent)].ForEach(p => | |||||
//{ | |||||
// p(@event, delegate (object[] args) | |||||
// { | |||||
// result.AddRange(args); | |||||
// }); | |||||
//}); | |||||
for (int i = _eventHandls[typeof(TEvent)].Count - 1; i >= 0; i--) | |||||
{ | |||||
_eventHandls[typeof(TEvent)][i](@event, delegate (object[] args) | |||||
{ | |||||
result.AddRange(args); | |||||
}); | |||||
} | |||||
} | |||||
eventCallBack.Invoke(result.ToArray()); | |||||
} | |||||
/// <summary> | |||||
/// 事件总线释放 | |||||
/// </summary> | |||||
public void Dispose() | |||||
{ | |||||
_eventHandls.Clear(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,16 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace BPASmartClient.Bus.EventBus | |||||
{ | |||||
/// <summary> | |||||
/// 事件接口 | |||||
/// </summary> | |||||
public interface IEvent | |||||
{ | |||||
int DeviceId { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,35 @@ | |||||
/* ============================================================================== | |||||
* 功能描述: | |||||
* 创 建 者:张原川 | |||||
* 创建日期:2016/10/10 16:50:12 | |||||
* ==============================================================================*/ | |||||
using BPASmartClient.Bus.EventBus; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
namespace LandStation.Bus | |||||
{ | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public static class IEventExtends | |||||
{ | |||||
#region Methods - Public | |||||
public static void Publish<TEvent>(this TEvent message) where TEvent : class, IEvent | |||||
{ | |||||
EventBus.GetInstance().Publish<TEvent>(message); | |||||
} | |||||
public static void Publish<TEvent>(this TEvent message, EventBus.EventCallBackHandle eventCallBack) where TEvent : class, IEvent | |||||
{ | |||||
EventBus.GetInstance().Publish<TEvent>(message, eventCallBack); | |||||
} | |||||
#endregion | |||||
} | |||||
} |
@@ -0,0 +1,9 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<TargetFramework>net6.0</TargetFramework> | |||||
<ImplicitUsings>enable</ImplicitUsings> | |||||
<Nullable>enable</Nullable> | |||||
</PropertyGroup> | |||||
</Project> |
@@ -0,0 +1,34 @@ | |||||
using System.Collections.Concurrent; | |||||
namespace BPASmartClient.DATABUS | |||||
{ | |||||
/// <summary> | |||||
/// 数据总线 | |||||
/// </summary> | |||||
public class Class_DataBus | |||||
{ | |||||
#region 单例模式 | |||||
public static Class_DataBus dataBus = null; | |||||
public static Class_DataBus GetInstance() | |||||
{ | |||||
if (dataBus == null) | |||||
{ | |||||
dataBus = new Class_DataBus(); | |||||
} | |||||
return dataBus; | |||||
} | |||||
#endregion | |||||
#region 基础配置 | |||||
#endregion | |||||
#region 实时数据->大数据量 | |||||
/// <summary> | |||||
/// 设备数据 | |||||
/// </summary> | |||||
public ConcurrentDictionary<string, object> Dic_DeviceData = new ConcurrentDictionary<string, object>(); //原始目标链表 | |||||
#endregion | |||||
} | |||||
} |
@@ -0,0 +1,9 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<TargetFramework>net6.0</TargetFramework> | |||||
<ImplicitUsings>enable</ImplicitUsings> | |||||
<Nullable>enable</Nullable> | |||||
</PropertyGroup> | |||||
</Project> |
@@ -0,0 +1,25 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.ComponentModel; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace BPASmartClient.MessageName | |||||
{ | |||||
/// <summary> | |||||
/// 数据订阅主题管理中心 | |||||
/// </summary> | |||||
public class DataName | |||||
{ | |||||
#region XX数据 | |||||
/// <summary> | |||||
/// xxx消息 | |||||
/// | |||||
/// </summary> | |||||
[Description("消息备注"), Browsable(true)] | |||||
public static string xxx = "xxx"; | |||||
#endregion | |||||
} | |||||
} |
@@ -0,0 +1,21 @@ | |||||
using System.ComponentModel; | |||||
namespace BPASmartClient.MessageName | |||||
{ | |||||
/// <summary> | |||||
/// 消息名称管理中心 | |||||
/// 特性:Description,消息备注 | |||||
/// Browsable,是否使用 | |||||
/// </summary> | |||||
public class MessageName | |||||
{ | |||||
#region XX消息 | |||||
/// <summary> | |||||
/// xxx消息 | |||||
/// | |||||
/// </summary> | |||||
[Description("消息备注"),Browsable(true)] | |||||
public static string xxx = "xxx"; | |||||
#endregion | |||||
} | |||||
} |
@@ -0,0 +1,197 @@ | |||||
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 BPASmartClient.SCADAControl | |||||
{ | |||||
/// <summary> | |||||
/// 新测试仪表盘 | |||||
/// </summary> | |||||
public class ArcGauge : Control, IExecutable | |||||
{ | |||||
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(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,10 @@ | |||||
using System.Windows; | |||||
[assembly: ThemeInfo( | |||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located | |||||
//(used if a resource is not found in the page, | |||||
// or application resource dictionaries) | |||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located | |||||
//(used if a resource is not found in the page, | |||||
// app, or any theme specific resource dictionaries) | |||||
)] |
@@ -0,0 +1,17 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<TargetFramework>net6.0-windows</TargetFramework> | |||||
<Nullable>enable</Nullable> | |||||
<UseWPF>true</UseWPF> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<None Remove="Images\光柱.png" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Resource Include="Images\光柱.png" /> | |||||
</ItemGroup> | |||||
</Project> |
@@ -0,0 +1,22 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace BPASmartClient.SCADAControl | |||||
{ | |||||
public interface IExecutable | |||||
{ | |||||
/// <summary> | |||||
/// 是否执行 | |||||
/// </summary> | |||||
bool IsExecuteState { get; set; } | |||||
/// <summary> | |||||
/// 运行程序 注册事件 | |||||
/// </summary> | |||||
void Register(); | |||||
string ControlType { get; } | |||||
} | |||||
} |
@@ -0,0 +1,42 @@ | |||||
<UserControl x:Class="BPASmartClient.SCADAControl.Silos" | |||||
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:BPASmartClient.SCADAControl" | |||||
mc:Ignorable="d" | |||||
d:DesignHeight="270" d:DesignWidth="180" > | |||||
<Grid> | |||||
<Grid.RowDefinitions> | |||||
<RowDefinition /> | |||||
<RowDefinition /> | |||||
</Grid.RowDefinitions> | |||||
<TextBlock | |||||
HorizontalAlignment="Center" | |||||
VerticalAlignment="Bottom" | |||||
Margin="0 0 0 35" | |||||
FontSize="25" | |||||
Foreground="#FFCCD61F" | |||||
Text="{Binding Title,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> | |||||
<TextBlock | |||||
Grid.Row="1" | |||||
Margin="0,25,0,0" | |||||
HorizontalAlignment="Center" | |||||
FontSize="20" | |||||
Foreground="#FF0084FF" | |||||
Text="{Binding Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> | |||||
<TextBlock | |||||
Grid.Row="1" | |||||
Margin="0,70,0,0" | |||||
HorizontalAlignment="Center" | |||||
FontSize="20" | |||||
Foreground="#FF0084FF" | |||||
Text="{Binding Text,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> | |||||
<Image | |||||
Grid.RowSpan="2" | |||||
Source="/BPASmartClient.SCADAControl;component/Images/光柱.png" | |||||
Stretch="Fill" /> | |||||
</Grid> | |||||
</UserControl> |
@@ -0,0 +1,96 @@ | |||||
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 BPASmartClient.SCADAControl | |||||
{ | |||||
/// <summary> | |||||
/// Silos.xaml 的交互逻辑 | |||||
/// 物料仓 | |||||
/// </summary> | |||||
public partial class Silos : UserControl, IExecutable | |||||
{ | |||||
public Silos() | |||||
{ | |||||
InitializeComponent(); | |||||
this.DataContext = this; | |||||
Width = 180; | |||||
Height = 270; | |||||
Value = 25.23; | |||||
Title = "香料"; | |||||
Text = "1 号仓"; | |||||
} | |||||
public string ControlType => "物料仓"; | |||||
private bool isExecuteState; | |||||
public bool IsExecuteState | |||||
{ | |||||
get { return isExecuteState; } | |||||
set | |||||
{ | |||||
isExecuteState = value; | |||||
if (IsExecuteState) | |||||
{ | |||||
IsEnabled = true; | |||||
Register(); | |||||
Style = null; | |||||
} | |||||
} | |||||
} | |||||
#region 属性 | |||||
[Category("值设定")] | |||||
public double Value | |||||
{ | |||||
get { return (double)GetValue(ValueProperty); } | |||||
set { SetValue(ValueProperty, value); } | |||||
} | |||||
public static readonly DependencyProperty ValueProperty = | |||||
DependencyProperty.Register("Value", typeof(double), typeof(Silos), new PropertyMetadata(0d, OnValueChanged)); | |||||
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as Silos)?.Refresh(); | |||||
[Category("值设定")] | |||||
public string Text | |||||
{ | |||||
get { return (string)GetValue(TextProperty); } | |||||
set { SetValue(TextProperty, value); } | |||||
} | |||||
public static readonly DependencyProperty TextProperty = | |||||
DependencyProperty.Register("Text", typeof(string), typeof(Silos), new PropertyMetadata(string.Empty)); | |||||
[Category("值设定")] | |||||
public string Title | |||||
{ | |||||
get { return (string)GetValue(TitleProperty); } | |||||
set { SetValue(TitleProperty, value); } | |||||
} | |||||
public static readonly DependencyProperty TitleProperty = | |||||
DependencyProperty.Register("Title", typeof(string), typeof(Silos), new PropertyMetadata(string.Empty)); | |||||
#endregion | |||||
#region 函数 | |||||
public void Refresh() | |||||
{ | |||||
} | |||||
#endregion | |||||
public void Register() | |||||
{ | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,96 @@ | |||||
<ResourceDictionary | |||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||||
xmlns:local="clr-namespace:BPASmartClient.SCADAControl" | |||||
xmlns:ctrl="clr-namespace:BPASmartClient.SCADAControl"> | |||||
<!--<Style TargetType="{x:Type local:CustomControl1}"> | |||||
<Setter Property="Template"> | |||||
<Setter.Value> | |||||
<ControlTemplate TargetType="{x:Type local:CustomControl1}"> | |||||
<Border Background="{TemplateBinding Background}" | |||||
BorderBrush="{TemplateBinding BorderBrush}" | |||||
BorderThickness="{TemplateBinding BorderThickness}"> | |||||
</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> | |||||
</ResourceDictionary> |
@@ -132,7 +132,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.JXJFoodBigSt | |||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.JXJFoodSmallStation", "BPASmartClient.JXJFoodSmallStation\BPASmartClient.JXJFoodSmallStation.csproj", "{D609C4CF-FA5C-4D39-B12F-07A60FFE5E40}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.JXJFoodSmallStation", "BPASmartClient.JXJFoodSmallStation\BPASmartClient.JXJFoodSmallStation.csproj", "{D609C4CF-FA5C-4D39-B12F-07A60FFE5E40}" | ||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPFDemo", "WPFDemo\WPFDemo.csproj", "{A456D582-D910-4CA2-8620-6D8F63344B47}" | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPFDemo", "WPFDemo\WPFDemo.csproj", "{A456D582-D910-4CA2-8620-6D8F63344B47}" | |||||
EndProject | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0.SCADA", "0.SCADA", "{7B0175AD-BB74-4A98-B9A7-1E289032485E}" | |||||
EndProject | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BPASmartClient.MessageName", "BPASmartClient.MessageName\BPASmartClient.MessageName.csproj", "{0D769B3B-0332-4DB9-A657-B739EDB28567}" | |||||
EndProject | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BPASmartClient.DATABUS", "BPASmartClient.DATABUS\BPASmartClient.DATABUS.csproj", "{7C1AF86E-867C-427E-90DB-6473D88F51EB}" | |||||
EndProject | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BPASmartClient.SCADAControl", "BPASmartClient.SCADAControl\BPASmartClient.SCADAControl.csproj", "{6A3FC66D-0B89-45E8-B39B-9D81538002D1}" | |||||
EndProject | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1.数据中心", "1.数据中心", "{7BED8969-7EA7-409C-8BBC-D2777ECDA2F1}" | |||||
EndProject | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2.消息名称管理", "2.消息名称管理", "{28BE5235-2399-4EBA-B1F0-88E0F32AC869}" | |||||
EndProject | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3.组态控件集", "3.组态控件集", "{5300552F-560D-474A-8D96-0A2747D08F64}" | |||||
EndProject | EndProject | ||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
@@ -1288,6 +1302,66 @@ Global | |||||
{A456D582-D910-4CA2-8620-6D8F63344B47}.Release|x64.Build.0 = Release|Any CPU | {A456D582-D910-4CA2-8620-6D8F63344B47}.Release|x64.Build.0 = Release|Any CPU | ||||
{A456D582-D910-4CA2-8620-6D8F63344B47}.Release|x86.ActiveCfg = Release|Any CPU | {A456D582-D910-4CA2-8620-6D8F63344B47}.Release|x86.ActiveCfg = Release|Any CPU | ||||
{A456D582-D910-4CA2-8620-6D8F63344B47}.Release|x86.Build.0 = Release|Any CPU | {A456D582-D910-4CA2-8620-6D8F63344B47}.Release|x86.Build.0 = Release|Any CPU | ||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|ARM.ActiveCfg = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|ARM.Build.0 = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|ARM64.ActiveCfg = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|ARM64.Build.0 = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|ARM.ActiveCfg = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|ARM.Build.0 = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|ARM64.ActiveCfg = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|ARM64.Build.0 = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|x64.Build.0 = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{0D769B3B-0332-4DB9-A657-B739EDB28567}.Release|x86.Build.0 = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|ARM.ActiveCfg = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|ARM.Build.0 = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|ARM64.ActiveCfg = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|ARM64.Build.0 = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|ARM.ActiveCfg = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|ARM.Build.0 = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|ARM64.ActiveCfg = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|ARM64.Build.0 = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|x64.Build.0 = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB}.Release|x86.Build.0 = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|ARM.ActiveCfg = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|ARM.Build.0 = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|ARM64.ActiveCfg = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|ARM64.Build.0 = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|ARM.ActiveCfg = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|ARM.Build.0 = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|ARM64.ActiveCfg = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|ARM64.Build.0 = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|x64.Build.0 = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1}.Release|x86.Build.0 = Release|Any CPU | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
@@ -1350,6 +1424,12 @@ Global | |||||
{FA695D7E-6F12-4483-A16D-8494609FAE68} = {8712125E-14CD-4E1B-A1CE-4BDE03805942} | {FA695D7E-6F12-4483-A16D-8494609FAE68} = {8712125E-14CD-4E1B-A1CE-4BDE03805942} | ||||
{D609C4CF-FA5C-4D39-B12F-07A60FFE5E40} = {8712125E-14CD-4E1B-A1CE-4BDE03805942} | {D609C4CF-FA5C-4D39-B12F-07A60FFE5E40} = {8712125E-14CD-4E1B-A1CE-4BDE03805942} | ||||
{A456D582-D910-4CA2-8620-6D8F63344B47} = {8712125E-14CD-4E1B-A1CE-4BDE03805942} | {A456D582-D910-4CA2-8620-6D8F63344B47} = {8712125E-14CD-4E1B-A1CE-4BDE03805942} | ||||
{0D769B3B-0332-4DB9-A657-B739EDB28567} = {28BE5235-2399-4EBA-B1F0-88E0F32AC869} | |||||
{7C1AF86E-867C-427E-90DB-6473D88F51EB} = {7BED8969-7EA7-409C-8BBC-D2777ECDA2F1} | |||||
{6A3FC66D-0B89-45E8-B39B-9D81538002D1} = {5300552F-560D-474A-8D96-0A2747D08F64} | |||||
{7BED8969-7EA7-409C-8BBC-D2777ECDA2F1} = {7B0175AD-BB74-4A98-B9A7-1E289032485E} | |||||
{28BE5235-2399-4EBA-B1F0-88E0F32AC869} = {7B0175AD-BB74-4A98-B9A7-1E289032485E} | |||||
{5300552F-560D-474A-8D96-0A2747D08F64} = {7B0175AD-BB74-4A98-B9A7-1E289032485E} | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(ExtensibilityGlobals) = postSolution | GlobalSection(ExtensibilityGlobals) = postSolution | ||||
SolutionGuid = {9AEC9B81-0222-4DE9-B642-D915C29222AC} | SolutionGuid = {9AEC9B81-0222-4DE9-B642-D915C29222AC} | ||||