diff --git a/BPASmartClient.Bus/BPASmartClient.Bus.csproj b/BPASmartClient.Bus/BPASmartClient.Bus.csproj new file mode 100644 index 00000000..cd3ccbd7 --- /dev/null +++ b/BPASmartClient.Bus/BPASmartClient.Bus.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + diff --git a/BPASmartClient.Bus/DataBus/DataBus.cs b/BPASmartClient.Bus/DataBus/DataBus.cs new file mode 100644 index 00000000..232bbc49 --- /dev/null +++ b/BPASmartClient.Bus/DataBus/DataBus.cs @@ -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, IDisposable + { + //原始数据总线 + private IDataBus _dataBus_rawdata; + //MAVLINK消息总线 + private IDataBus _dataBus_mavMessage; + //参数总线 + private IDataBus _dataBus_parameter; + //调试消息总线 + private IDataBus _dataBus_message; + + /// + /// 数据总线初始化 + /// + public void Initialize() + { + _dataBus_rawdata = new DataBus_Byte(); + _dataBus_mavMessage = new DataBus_Currency(); + _dataBus_parameter = new DataBus_Currency(); + _dataBus_message = new DataBus_Currency(); + } + + /// + /// 总线开启 + /// + 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, "数据总线监控"); + } + + /// + /// 根据数据类型放入数据到对应总线 + /// + /// 数据实际类型 + /// 数据 + /// 数据业务类型 + public void Put(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; + } + } + + /// + /// 订阅数据 + /// + /// 数据实际类型 + /// 接收数据推送回调 + /// 数据业务类型 + public void Subscribe(Action action, SimpleDataType dataType) + { + switch (dataType) + { + case SimpleDataType.RAW_DATA: + ((ISimpleDataBus)_dataBus_rawdata).Subscribe(action); + break; + case SimpleDataType.MAV_MESSAGE_DATA: + ((ISimpleDataBus)_dataBus_mavMessage).Subscribe(action); + break; + case SimpleDataType.PARAMETER: + ((ISimpleDataBus)_dataBus_parameter).Subscribe(action); + break; + case SimpleDataType.MESSAGE_DATA: + ((ISimpleDataBus)_dataBus_message).Subscribe(action); + break; + } + } + + /// + /// 订阅数据 + /// + /// 数据实际类型 + /// 接收数据推送回调 + /// 数据业务类型 + public void UnSubscribe(Action action, SimpleDataType dataType) + { + switch (dataType) + { + case SimpleDataType.RAW_DATA: + ((ISimpleDataBus)_dataBus_rawdata).UnSubcribe(action); + break; + case SimpleDataType.MAV_MESSAGE_DATA: + ((ISimpleDataBus)_dataBus_mavMessage).UnSubcribe(action); + break; + case SimpleDataType.PARAMETER: + ((ISimpleDataBus)_dataBus_parameter).UnSubcribe(action); + break; + case SimpleDataType.MESSAGE_DATA: + ((ISimpleDataBus)_dataBus_message).UnSubcribe(action); + break; + } + } + + /// + /// 订阅数据 + /// + /// 数据实际类型 + /// 接收数据推送回调 + /// 数据业务类型 + public void Subscribe(Action action, SimpleDataType dataType) + { + switch (dataType) + { + case SimpleDataType.RAW_DATA: + ((ISimpleDataBus)_dataBus_rawdata).Subscribe(action); + break; + case SimpleDataType.MAV_MESSAGE_DATA: + ((ISimpleDataBus)_dataBus_mavMessage).Subscribe(action); + break; + case SimpleDataType.PARAMETER: + ((ISimpleDataBus)_dataBus_parameter).Subscribe(action); + break; + case SimpleDataType.MESSAGE_DATA: + ((ISimpleDataBus)_dataBus_message).Subscribe(action); + break; + } + } + + /// + /// 订阅数据 + /// + /// 数据实际类型 + /// 接收数据推送回调 + /// 数据业务类型 + public void UnSubscribe(Action action, SimpleDataType dataType) + { + switch (dataType) + { + case SimpleDataType.RAW_DATA: + ((ISimpleDataBus)_dataBus_rawdata).UnSubcribe(action); + break; + case SimpleDataType.MAV_MESSAGE_DATA: + ((ISimpleDataBus)_dataBus_mavMessage).UnSubcribe(action); + break; + case SimpleDataType.PARAMETER: + ((ISimpleDataBus)_dataBus_parameter).UnSubcribe(action); + break; + case SimpleDataType.MESSAGE_DATA: + ((ISimpleDataBus)_dataBus_message).UnSubcribe(action); + break; + } + } + + /// + /// 获取一个数据 + /// + /// 数据实际类型 + /// 数据业务类型 + /// 一个数据 + public byte GetRawdata() + { + return ((IGivenDataBus)_dataBus_rawdata).Get(); + } + + /// + /// 获取多个数据 + /// + /// 数据实际类型 + /// 数据业务类型 + /// 获取数据长度 + /// 一个数据 + public byte[] GetRawdata(int length) + { + return ((IGivenDataBus)_dataBus_rawdata).Get(length); + } + + /// + /// 释放数据总线 + /// + public void Dispose() + { + _dataBus_rawdata.StopBus(); + _dataBus_mavMessage.StopBus(); + _dataBus_message.StopBus(); + _dataBus_parameter.StopBus(); + } + } +} diff --git a/BPASmartClient.Bus/DataBus/DataBus_Byte.cs b/BPASmartClient.Bus/DataBus/DataBus_Byte.cs new file mode 100644 index 00000000..79bdf175 --- /dev/null +++ b/BPASmartClient.Bus/DataBus/DataBus_Byte.cs @@ -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, IGivenDataBus + { + //接收数据缓冲(用以Get) + //protected CircularBuffer _givenDataPool = new CircularBuffer(1 * 1024 * 1024); + protected ConcurrentQueue _givenDataPool = new ConcurrentQueue(); + + public new int DataCount { get { return _givenDataPool.Count; } } + + /// + /// 重写Put方法,加入givenDataPool + /// + public new void Put(byte data) + { + if (!_running) + return; + if (_multDataHandlers.Count > 0 || _singleDataHandlers.Count > 0) + _dataPool.Enqueue(data); + _givenDataPool.Enqueue(data); + } + + /// + /// 重写Put方法,加入givenDataPool + /// + 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); + } + + /// + /// 数据取出 + /// + public byte Get() + { + agin: + if (_givenDataPool.Count <= 0) + { + Thread.Sleep(5); + goto agin; + } + byte res; + while (!_givenDataPool.TryDequeue(out res)) ; + return res; + } + + /// + /// 数据取出 + /// + 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); + } + } +} diff --git a/BPASmartClient.Bus/DataBus/DataBus_Currency.cs b/BPASmartClient.Bus/DataBus/DataBus_Currency.cs new file mode 100644 index 00000000..d3d20b97 --- /dev/null +++ b/BPASmartClient.Bus/DataBus/DataBus_Currency.cs @@ -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 : ISimpleDataBus + { + //接收数据缓冲 + //protected CircularBuffer _dataPool = new CircularBuffer(1 * 1024 * 1024); + protected ConcurrentQueue _dataPool = new ConcurrentQueue(); + //订阅数据回调集合 + protected List> _multDataHandlers = new List>(); + protected List> _singleDataHandlers = new List>(); + //订阅与推送数据信号量 + 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; } } + + /// + /// 终止事件总线 + /// + public void Dispose() + { + StopBus(); + } + + /// + /// 数据存入 + /// + public void Put(TData data) + { + if (!_running) + return; + if (_multDataHandlers.Count > 0 || _singleDataHandlers.Count > 0) + _dataPool.Enqueue(data); + } + + /// + /// 数据存入 + /// + public void Put(TData[] data) + { + if (!_running) + return; + if (_multDataHandlers.Count > 0 || _singleDataHandlers.Count > 0) + foreach (var item in data) + _dataPool.Enqueue(item); + } + + /// + /// 开启总线 + /// + public void StartBus() + { + _running = true; + List items = new List(); + _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; + } + + /// + /// 数据订阅 + /// + /// 接收数据回调 + public void Subscribe(Action action) + { + if (_singleDataHandlers.Contains(action)) + return; + _are.Reset(); + _singleDataHandlers.Add(action); + _are.Set(); + } + + /// + /// 数据订阅 + /// + /// 接收数据回调 + public void Subscribe(Action action) + { + if (_multDataHandlers.Contains(action)) + return; + _are.Reset(); + _multDataHandlers.Add(action); + _are.Set(); + } + + /// + /// 取消数据订阅 + /// + /// 接收数据回调 + public void UnSubcribe(Action action) + { + if (!_singleDataHandlers.Contains(action)) + return; + _are.Reset(); + _singleDataHandlers.Remove(action); + _are.Set(); + } + + /// + /// 取消数据订阅 + /// + /// 接收数据回调 + public void UnSubcribe(Action action) + { + if (!_multDataHandlers.Contains(action)) + return; + _are.Reset(); + _multDataHandlers.Remove(action); + _are.Set(); + } + } +} diff --git a/BPASmartClient.Bus/DataBus/Executer.cs b/BPASmartClient.Bus/DataBus/Executer.cs new file mode 100644 index 00000000..3aa83f59 --- /dev/null +++ b/BPASmartClient.Bus/DataBus/Executer.cs @@ -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 +{ + /// + /// 线程集中处理委托 + /// + /// + public delegate void ActionKeyHandle(string action); + public delegate void ThreadExceptionHandle(string action, Exception ex); + public delegate void ThreadExitHandle(string action); + /// + /// 执行器 + /// + public class Executer : Singleton + { + private System.Timers.Timer _timer4Monitor = new System.Timers.Timer(1000); + private ConcurrentDictionary _actions = new ConcurrentDictionary(); + private object _async = new object(); + public event ThreadExceptionHandle OnThreadException; + public event ThreadExitHandle ThreadExit; + /// + /// 构造器 + /// + public Executer() + { + } + + /// + /// + /// + public void Dispose() + { + _timer4Monitor.Stop(); + foreach (var th in _actions) + { + try { th.Value.Abort(); } + catch (ThreadAbortException) { } + } + } + /// + /// + /// + /// + public List GetActionInfos() + { + Monitor.TryEnter(_async, 200); + var actionInfos = _actions.Values.ToList(); + Monitor.Exit(_async); + return actionInfos; + } + + + /// + /// + /// + /// + public void Abort(string key) + { + Monitor.TryEnter(_async, 200); + if (_actions.ContainsKey(key)) + { + try { _actions[key].Abort(); } + catch (ThreadAbortException) { } + } + Monitor.Exit(_async); + } + /// + /// + /// + /// + /// + public bool ContainsKey(string key) + { + Monitor.TryEnter(_async, 200); + var item = _actions[key]; + Monitor.Exit(_async); + if (null != item) + { + return true; + } + return false; + } + /// + /// + /// + /// + /// + /// + /// + 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); + } + /// + /// + /// + /// + /// + /// + public bool StartWhiteReturn(Func action, int timeout = 3) + { + DateTime beginTime = DateTime.Now; + bool doResult = false; + while (DateTime.Now.Subtract(beginTime).TotalSeconds <= 3 && !doResult) + { + doResult = action(); + } + return doResult; + } + /// + /// + /// + public event ActionKeyHandle ActionAbort; + /// + /// + /// + public event ActionKeyHandle ActionStarted; + } +} diff --git a/BPASmartClient.Bus/DataBus/IDataBus.cs b/BPASmartClient.Bus/DataBus/IDataBus.cs new file mode 100644 index 00000000..34519c41 --- /dev/null +++ b/BPASmartClient.Bus/DataBus/IDataBus.cs @@ -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 +{ + /// + /// 数据总线接口 + /// + public interface IDataBus + { + /// + /// 多数据订阅数量 + /// + int MultSubscriberCount { get; } + /// + /// 单数据订阅数量 + /// + int SingleSubscriberCount { get; } + /// + /// 数据量 + /// + int DataCount { get; } + /// + /// 开启总线 + /// + void StartBus(); + + /// + /// 关闭总线 + /// + void StopBus(); + + /// + /// 数据放入总线 + /// + /// 数据 + void Put(TData data); + /// + /// 数据放入总线 + /// + /// 数据 + void Put(TData[] data); + } +} diff --git a/BPASmartClient.Bus/DataBus/IGivenDataBus.cs b/BPASmartClient.Bus/DataBus/IGivenDataBus.cs new file mode 100644 index 00000000..5faad71f --- /dev/null +++ b/BPASmartClient.Bus/DataBus/IGivenDataBus.cs @@ -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: IDataBus + { + /// + /// 数据取出 + /// + /// + TData Get(); + + /// + /// 数据取出 + /// + /// + TData[] Get(int count); + } +} diff --git a/BPASmartClient.Bus/DataBus/ISimpleDataBus.cs b/BPASmartClient.Bus/DataBus/ISimpleDataBus.cs new file mode 100644 index 00000000..a1e71440 --- /dev/null +++ b/BPASmartClient.Bus/DataBus/ISimpleDataBus.cs @@ -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: IDataBus,IDisposable + { + /// + /// 订阅总线数据 + /// + /// 数据类型 + void Subscribe(Action action); + void Subscribe(Action action); + + /// + /// 取消订阅数据 + /// + /// 数据类型 + void UnSubcribe(Action action); + void UnSubcribe(Action action); + + } +} diff --git a/BPASmartClient.Bus/DataBus/SimpleDataType.cs b/BPASmartClient.Bus/DataBus/SimpleDataType.cs new file mode 100644 index 00000000..f3a609ee --- /dev/null +++ b/BPASmartClient.Bus/DataBus/SimpleDataType.cs @@ -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 + { + /// + /// 原始数据总线 + /// + RAW_DATA, + /// + /// MAVLINK消息总线 + /// + MAV_MESSAGE_DATA, + /// + /// 全局状态数据总线 + /// + STATUS_DATA, + /// + /// 参数总线 + /// + PARAMETER, + /// + /// 调试消息总线 + /// + MESSAGE_DATA + } +} diff --git a/BPASmartClient.Bus/EventBus/EventBus.cs b/BPASmartClient.Bus/EventBus/EventBus.cs new file mode 100644 index 00000000..1b60cba2 --- /dev/null +++ b/BPASmartClient.Bus/EventBus/EventBus.cs @@ -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 + { + //事件处理委托 + public delegate void EventCallBackHandle(params object[] args); + //事件处理委托 + public delegate void EventHandle(IEvent @event, EventCallBackHandle callBack = null); + //事件订阅者集合 + private ConcurrentDictionary> _eventHandls = new ConcurrentDictionary>(); + + /// + /// 事件订阅 + /// + public void Subscribe(EventHandle handle) + { + if (!_eventHandls.ContainsKey(typeof(TEvent))) + _eventHandls.TryAdd(typeof(TEvent), new List()); + lock (_eventHandls) + _eventHandls[typeof(TEvent)].Add(handle); + } + + /// + /// 事件退订 + /// + public void UnSubscribe(EventHandle handle) + { + if (_eventHandls.ContainsKey(typeof(TEvent))) + { + if (_eventHandls[typeof(TEvent)].Contains(handle)) + { + lock (_eventHandls) + _eventHandls[typeof(TEvent)].Remove(handle); + } + } + } + + /// + /// 事件发布,不带返回 + /// + public void Publish(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); + //}); + } + } + + /// + /// 事件发布,带返回 + /// + public void Publish(TEvent @event, EventCallBackHandle eventCallBack) where TEvent : IEvent + { + List result = new List(); + 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()); + } + + /// + /// 事件总线释放 + /// + public void Dispose() + { + _eventHandls.Clear(); + } + } + +} diff --git a/BPASmartClient.Bus/EventBus/IEvent.cs b/BPASmartClient.Bus/EventBus/IEvent.cs new file mode 100644 index 00000000..cffc3ad9 --- /dev/null +++ b/BPASmartClient.Bus/EventBus/IEvent.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.Bus.EventBus +{ + /// + /// 事件接口 + /// + public interface IEvent + { + int DeviceId { get; set; } + } +} diff --git a/BPASmartClient.Bus/EventBus/IEventExtends.cs b/BPASmartClient.Bus/EventBus/IEventExtends.cs new file mode 100644 index 00000000..9dea6010 --- /dev/null +++ b/BPASmartClient.Bus/EventBus/IEventExtends.cs @@ -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 +{ + /// + /// + /// + public static class IEventExtends + { + + #region Methods - Public + + public static void Publish(this TEvent message) where TEvent : class, IEvent + { + EventBus.GetInstance().Publish(message); + } + + public static void Publish(this TEvent message, EventBus.EventCallBackHandle eventCallBack) where TEvent : class, IEvent + { + EventBus.GetInstance().Publish(message, eventCallBack); + } + + #endregion + } +} diff --git a/BPASmartClient.DATABUS/BPASmartClient.DATABUS.csproj b/BPASmartClient.DATABUS/BPASmartClient.DATABUS.csproj new file mode 100644 index 00000000..132c02c5 --- /dev/null +++ b/BPASmartClient.DATABUS/BPASmartClient.DATABUS.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/BPASmartClient.DATABUS/Class_DataBus.cs b/BPASmartClient.DATABUS/Class_DataBus.cs new file mode 100644 index 00000000..ade24c63 --- /dev/null +++ b/BPASmartClient.DATABUS/Class_DataBus.cs @@ -0,0 +1,34 @@ +using System.Collections.Concurrent; + +namespace BPASmartClient.DATABUS +{ + /// + /// 数据总线 + /// + 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 实时数据->大数据量 + /// + /// 设备数据 + /// + public ConcurrentDictionary Dic_DeviceData = new ConcurrentDictionary(); //原始目标链表 + #endregion + } +} \ No newline at end of file diff --git a/BPASmartClient.MessageName/BPASmartClient.MessageName.csproj b/BPASmartClient.MessageName/BPASmartClient.MessageName.csproj new file mode 100644 index 00000000..132c02c5 --- /dev/null +++ b/BPASmartClient.MessageName/BPASmartClient.MessageName.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/BPASmartClient.MessageName/DataName.cs b/BPASmartClient.MessageName/DataName.cs new file mode 100644 index 00000000..b2f59608 --- /dev/null +++ b/BPASmartClient.MessageName/DataName.cs @@ -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 +{ + /// + /// 数据订阅主题管理中心 + /// + public class DataName + { + #region XX数据 + /// + /// xxx消息 + /// + /// + [Description("消息备注"), Browsable(true)] + public static string xxx = "xxx"; + #endregion + + } +} diff --git a/BPASmartClient.MessageName/MessageName.cs b/BPASmartClient.MessageName/MessageName.cs new file mode 100644 index 00000000..a43e9480 --- /dev/null +++ b/BPASmartClient.MessageName/MessageName.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; + +namespace BPASmartClient.MessageName +{ + /// + /// 消息名称管理中心 + /// 特性:Description,消息备注 + /// Browsable,是否使用 + /// + public class MessageName + { + #region XX消息 + /// + /// xxx消息 + /// + /// + [Description("消息备注"),Browsable(true)] + public static string xxx = "xxx"; + #endregion + } +} \ No newline at end of file diff --git a/BPASmartClient.SCADAControl/ArcGauge.cs b/BPASmartClient.SCADAControl/ArcGauge.cs new file mode 100644 index 00000000..51fe9932 --- /dev/null +++ b/BPASmartClient.SCADAControl/ArcGauge.cs @@ -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 +{ + /// + /// 新测试仪表盘 + /// + 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 textLabels = new List(); + 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(); + } + } +} diff --git a/BPASmartClient.SCADAControl/AssemblyInfo.cs b/BPASmartClient.SCADAControl/AssemblyInfo.cs new file mode 100644 index 00000000..8b5504ec --- /dev/null +++ b/BPASmartClient.SCADAControl/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/BPASmartClient.SCADAControl/BPASmartClient.SCADAControl.csproj b/BPASmartClient.SCADAControl/BPASmartClient.SCADAControl.csproj new file mode 100644 index 00000000..6ba18c27 --- /dev/null +++ b/BPASmartClient.SCADAControl/BPASmartClient.SCADAControl.csproj @@ -0,0 +1,17 @@ + + + + net6.0-windows + enable + true + + + + + + + + + + + diff --git a/BPASmartClient.SCADAControl/IExecutable.cs b/BPASmartClient.SCADAControl/IExecutable.cs new file mode 100644 index 00000000..14f2b781 --- /dev/null +++ b/BPASmartClient.SCADAControl/IExecutable.cs @@ -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 + { + /// + /// 是否执行 + /// + bool IsExecuteState { get; set; } + /// + /// 运行程序 注册事件 + /// + void Register(); + + string ControlType { get; } + } +} diff --git a/BPASmartClient.SCADAControl/Images/光柱.png b/BPASmartClient.SCADAControl/Images/光柱.png new file mode 100644 index 00000000..da3a0b42 Binary files /dev/null and b/BPASmartClient.SCADAControl/Images/光柱.png differ diff --git a/BPASmartClient.SCADAControl/Silos.xaml b/BPASmartClient.SCADAControl/Silos.xaml new file mode 100644 index 00000000..39b60ba8 --- /dev/null +++ b/BPASmartClient.SCADAControl/Silos.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + diff --git a/BPASmartClient.SCADAControl/Silos.xaml.cs b/BPASmartClient.SCADAControl/Silos.xaml.cs new file mode 100644 index 00000000..2435dc5d --- /dev/null +++ b/BPASmartClient.SCADAControl/Silos.xaml.cs @@ -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 +{ + /// + /// Silos.xaml 的交互逻辑 + /// 物料仓 + /// + 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() + { + } + } +} diff --git a/BPASmartClient.SCADAControl/Themes/Generic.xaml b/BPASmartClient.SCADAControl/Themes/Generic.xaml new file mode 100644 index 00000000..7035bccf --- /dev/null +++ b/BPASmartClient.SCADAControl/Themes/Generic.xaml @@ -0,0 +1,96 @@ + + + + + diff --git a/SmartClient.sln b/SmartClient.sln index e2b2a72e..cd1980a2 100644 --- a/SmartClient.sln +++ b/SmartClient.sln @@ -132,7 +132,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.JXJFoodBigSt EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.JXJFoodSmallStation", "BPASmartClient.JXJFoodSmallStation\BPASmartClient.JXJFoodSmallStation.csproj", "{D609C4CF-FA5C-4D39-B12F-07A60FFE5E40}" 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 Global 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|x86.ActiveCfg = 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 GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1350,6 +1424,12 @@ Global {FA695D7E-6F12-4483-A16D-8494609FAE68} = {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} + {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 GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9AEC9B81-0222-4DE9-B642-D915C29222AC}