Sic.Framework-Nanjing-Baishi/UIDebug/SicUI/MainViewModel.cs

802 lines
26 KiB
C#
Raw Normal View History

using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using Caliburn.Micro;
using MECF.Framework.Common.Account.Extends;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.Common.OperationCenter;
using MECF.Framework.UI.Client.CenterViews.LogOnOff;
using MECF.Framework.UI.Client.ClientBase;
using MECF.Framework.UI.Core.Accounts;
using OpenSEMI.ClientBase.Command;
using OpenSEMI.ClientBase.Utility;
using SciChart.Charting.ChartModifiers;
using SciChart.Charting.Visuals;
using SciChart.Charting.Visuals.Annotations;
using SciChart.Charting.Visuals.Axes;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Sicentury.Core.Collections;
using Cali = Caliburn.Micro.Core;
namespace SicUI.Client
{
public class TimeredMainViewModel : Cali.Conductor<Cali.Screen>.Collection.OneActive
{
private readonly PeriodicJob _timer;
private readonly ConcurrentBag<string> _subscribedKeys = new ConcurrentBag<string>();
private readonly Func<object, bool> _isSubscriptionAttribute;
private readonly Func<MemberInfo, bool> _hasSubscriptionAttribute;
public TimeredMainViewModel()
{
_timer = new PeriodicJob(1000, OnTimer, "UIUpdaterThread - " + GetType().Name);
_isSubscriptionAttribute = attribute => attribute is SubscriptionAttribute;
_hasSubscriptionAttribute = mi => mi.GetCustomAttributes(false).Any(_isSubscriptionAttribute);
SubscribeKeys(this);
}
[StructLayout(LayoutKind.Sequential)]
internal struct LASTINPUTINFO
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int dwTime;
}
[DllImport("user32.dll")]
internal static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
/// <summary>
/// 获取鼠标键盘不活动的时间
/// </summary>
/// <returns>结果</returns>
public static int GetLastInputTime()
{
var lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = Marshal.SizeOf(lastInputInfo);
lastInputInfo.dwTime = 0;
var idleTime = 0;
if (GetLastInputInfo(ref lastInputInfo))
{
idleTime = Environment.TickCount - lastInputInfo.dwTime;
}
return ((idleTime > 0) ? (idleTime / 1000) : 0);
}
protected virtual bool OnTimer()
{
try
{
Poll();
}
catch (Exception ex)
{
LOG.Error(ex.Message);
}
return true;
}
public virtual void EnableTimer(bool enable)
{
if (enable) _timer.Start();
else _timer.Pause();
}
protected virtual void Poll()
{
if (_subscribedKeys.Count > 0)
{
Dictionary<string, object> result = QueryDataClient.Instance.Service.PollData(_subscribedKeys);
if (result == null)
{
LOG.Error("获取RT数据失败");
return;
}
if (result.Count != _subscribedKeys.Count)
{
string unknowKeys = string.Empty;
foreach (string key in _subscribedKeys)
{
if (!result.ContainsKey(key))
{
unknowKeys += key + "\r\n";
}
}
//System.Diagnostics.Debug.Assert(false, unknowKeys);
}
InvokeBeforeUpdateProperty(result);
UpdateValue(result);
Application.Current.Dispatcher.Invoke(new System.Action(() =>
{
InvokePropertyChanged();
InvokeAfterUpdateProperty(result);
}));
}
}
private void InvokePropertyChanged()
{
Refresh();
}
protected virtual void InvokeBeforeUpdateProperty(Dictionary<string, object> data)
{
}
protected virtual void InvokeAfterUpdateProperty(Dictionary<string, object> data)
{
}
private void UpdateValue(Dictionary<string, object> data)
{
if (data == null)
return;
UpdateSubscribe(data, this);
var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttribute<SubscriptionModuleAttribute>() != null);
foreach (var property in properties)
{
var moduleAttr = property.GetCustomAttribute<SubscriptionModuleAttribute>();
UpdateSubscribe(data, property.GetValue(this), moduleAttr.Module);
}
}
protected void Subscribe(string key)
{
if (!string.IsNullOrEmpty(key))
{
_subscribedKeys.Add(key);
}
}
public void SubscribeKeys(TimeredMainViewModel target)
{
Parallel.ForEach(target.GetType().GetProperties().Where(_hasSubscriptionAttribute),
property =>
{
SubscriptionAttribute subscription = property.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute;
string key = subscription.ModuleKey;
if (!_subscribedKeys.Contains(key))
_subscribedKeys.Add(key);
});
Parallel.ForEach(target.GetType().GetFields().Where(_hasSubscriptionAttribute),
method =>
{
SubscriptionAttribute subscription = method.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute;
string key = subscription.ModuleKey;
if (!_subscribedKeys.Contains(key))
_subscribedKeys.Add(key);
});
}
public void UpdateSubscribe(Dictionary<string, object> data, object target, string module = null)
{
Parallel.ForEach(target.GetType().GetProperties().Where(_hasSubscriptionAttribute),
property =>
{
PropertyInfo pi = (PropertyInfo)property;
SubscriptionAttribute subscription = property.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute;
string key = subscription.ModuleKey;
key = module == null ? key : string.Format("{0}.{1}", module, key);
if (_subscribedKeys.Contains(key) && data.ContainsKey(key))
{
try
{
var convertedValue = Convert.ChangeType(data[key], pi.PropertyType);
var originValue = Convert.ChangeType(pi.GetValue(target, null), pi.PropertyType);
if (originValue != convertedValue)
{
if (pi.Name == "PumpLimitSetPoint")
pi.SetValue(target, convertedValue, null);
else
pi.SetValue(target, convertedValue, null);
}
}
catch (Exception ex)
{
LOG.Error("由RT返回的数据更新失败" + key, ex);
}
}
});
Parallel.ForEach(target.GetType().GetFields().Where(_hasSubscriptionAttribute),
property =>
{
FieldInfo pi = (FieldInfo)property;
SubscriptionAttribute subscription = property.GetCustomAttributes(false).First(_isSubscriptionAttribute) as SubscriptionAttribute;
string key = subscription.ModuleKey;
if (_subscribedKeys.Contains(key) && data.ContainsKey(key))
{
try
{
var convertedValue = Convert.ChangeType(data[key], pi.FieldType);
pi.SetValue(target, convertedValue);
}
catch (Exception ex)
{
LOG.Error("由RT返回的数据更新失败" + key, ex);
}
}
});
}
}
public class MainViewModel : TimeredMainViewModel
{
#region Menus
public string NowDateTime { get; set; }
private bool _isLogin = false;
public bool IsLogin
{
get => _isLogin;
set { _isLogin = value; NotifyOfPropertyChange(); }
}
private List<Role> _roles;
public List<Role> Roles
{
get => _roles;
set { _roles = value; RaisePropertyChangedEventImmediately(nameof(Roles)); }
}
private ICommand _menuItemClickCommand;
public ICommand MenuItemClickCommand
{
get
{
if (_menuItemClickCommand == null)
_menuItemClickCommand = new BaseCommand<AppMenu>(SwitchMenuItem);
return _menuItemClickCommand;
}
}
private ICommand _mainMenuItemClickCommand;
public ICommand MainMenuItemClickCommand
{
get
{
if (_mainMenuItemClickCommand == null)
_mainMenuItemClickCommand = new BaseCommand<AppMenu>(MainSwitchMenuItem);
return _mainMenuItemClickCommand;
}
}
public List<AppMenu> MenuItems
{
get => _menuItems;
set { _menuItems = value; NotifyOfPropertyChange(); }
}
public List<AppMenu> SubMenuItems
{
get => _subMenuItems;
set { _subMenuItems = value; NotifyOfPropertyChange(); }
}
public ObservableCollection<AppMenu> HistoryMenus
{
get => _historyItems;
set { _historyItems = value; NotifyOfPropertyChange(); }
}
public string Context
{
get => _context;
set { _context = value; NotifyOfPropertyChange(); }
}
public BaseModel CurrentViewModel { get; private set; }
public UserContext User => BaseApp.Instance.UserContext;
private AppMenu _currentMenuItem;
private List<AppMenu> _menuItems;
private List<AppMenu> _subMenuItems;
private ObservableCollection<AppMenu> _historyItems;
private string _context;
private MainView _view;
private Dictionary<Type, BaseModel> _models;
#endregion
public bool IsAutoLogout { get; set; }
public int LogoutTime { get; set; }
//public ObservableCollection<EventItem> WarnEventLogList { get; set; }
private DelayedPresentRollingObservableCollection<EventItem> EventLogList { get; }
/// <summary>
/// 用于在主界面显示Event Log的视图。
/// 通过该视图筛选IsAlarm条目。
/// </summary>
public ICollectionView EventLogsView { get; }
private bool _isShowAlarmEventOnly;
/// <summary>
/// IsAlarm CheckBox绑定到这里直接从<see cref="EventLogsView"/>中过滤所需的数据。
/// </summary>
public bool IsShowAlarmEventOnly
{
get => _isShowAlarmEventOnly;
set
{
_isShowAlarmEventOnly = value;
if (_isShowAlarmEventOnly)
{
EventLogsView.Filter = item =>
{
if (item is EventItem ei)
{
return ei.Level == EventLevel.Alarm;
}
return false;
};
}
else
{
EventLogsView.Filter = null;
}
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsShowAlarmEventOnly)));
}
}
public Visibility AllEventsVisibility { get; set; }
public Visibility WarnEventsVisibility { get; set; }
public string SoftwareVersion
{
get;
set;
}
private AppMenu _alarmMenu;
public MainViewModel()
{
BaseApp.Instance.Initialize();
((ClientApp)BaseApp.Instance).ViewModelSwitcher = this;
_models = new Dictionary<Type, BaseModel>();
SoftwareVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
/*EventClient.Instance.OnEvent += Instance_OnEvent;
EventClient.Instance.OnDisconnectedWithRT += Instance_OnDisconnectedWithRT;
EventClient.Instance.Start();*/
}
private void Instance_OnDisconnectedWithRT()
{
MessageBox.Show("Disconnected with RT, UI will exit", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
Environment.Exit(0);
}
public void ShowAlarmEvents()
{
AllEventsVisibility = Visibility.Hidden;
WarnEventsVisibility = Visibility.Visible;
NotifyOfPropertyChange(nameof(AllEventsVisibility));
NotifyOfPropertyChange(nameof(WarnEventsVisibility));
}
public void ShowAllEvents()
{
AllEventsVisibility = Visibility.Visible;
WarnEventsVisibility = Visibility.Hidden;
NotifyOfPropertyChange(nameof(AllEventsVisibility));
NotifyOfPropertyChange(nameof(WarnEventsVisibility));
}
private void Instance_OnEvent(EventItem obj)
{
switch (obj.Type)
{
case EventType.EventUI_Notify:
LogEvent(obj);
break;
case EventType.Dialog_Nofity:
//PopDialog(obj);
break;
case EventType.KickOut_Notify:
if (obj.Description == "ShutDown")
{
AccountClient.Instance.Service.LogoutEx(BaseApp.Instance.UserContext.LoginName, BaseApp.Instance.UserContext.LoginId);
_shutdownThread = ShutdownExecute;
_shutdownThread.BeginInvoke(ShutdownCallBack, _shutdownThread);
}
break;
case EventType.Sound_Notify:
break;
case EventType.UIMessage_Notify:
//PopUIMessage(obj);
break;
}
}
private void LogEvent(EventItem obj)
{
if (obj.Type != EventType.EventUI_Notify)
return;
EventLogList.Add(obj);
}
public void SetModuleOnline(string module)
{
if (MessageBoxResult.Yes == MessageBox.Show($"Set {module} Online ?", "", MessageBoxButton.YesNo, MessageBoxImage.Warning))
{
InvokeClient.Instance.Service.DoOperation($"{module}.SetOnline");
}
}
public void SetModuleOffline(string module)
{
if (MessageBoxResult.Yes == MessageBox.Show($"Set {module} Offline ?", "", MessageBoxButton.YesNo, MessageBoxImage.Warning))
{
InvokeClient.Instance.Service.DoOperation($"{module}.SetOffline");
}
}
public void Logout()
{
OnLogoutCommand();
}
public void OnLogoutCommand()
{
WindowManager windowmanager = new WindowManager();
var logoffViewmodel = new LogoffViewModel();
windowmanager.ShowDialog(logoffViewmodel);
BaseApp.Instance.UserMode = logoffViewmodel.DialogResult;
switch (logoffViewmodel.DialogResult)
{
case UserMode.Logoff:
Logoff();
break;
case UserMode.Exit:
AccountClient.Instance.Service.LogoutEx(BaseApp.Instance.UserContext.LoginName, BaseApp.Instance.UserContext.LoginId);
BaseApp.Instance.UserMode = UserMode.Exit;
LOG.Info(string.Format("{0} exit as {1}", BaseApp.Instance.UserContext.LoginName, BaseApp.Instance.UserContext.RoleName));
TryClose();
break;
case UserMode.Shutdown:
InvokeClient.Instance.Service.DoOperation("System.ShutDown");
break;
}
}
public void Logoff()
{
BaseApp.Instance.UserMode = UserMode.Logoff;
if (BaseApp.Instance.UserContext.IsLogin)
{
try
{
AccountClient.Instance.Service.LogoutEx(BaseApp.Instance.UserContext.LoginName, BaseApp.Instance.UserContext.LoginId);
BaseApp.Instance.UserContext.IsLogin = false;
LOG.Info(string.Format("{0} logoff as {1}", BaseApp.Instance.UserContext.LoginName, BaseApp.Instance.UserContext.RoleName));
}
catch (Exception exp)
{
LOG.Write(exp);
}
}
IsLogin = false; //no independent login page
Roles = RoleAccountProvider.Instance.GetRoles();
}
public void Reset()
{
InvokeClient.Instance.Service.DoOperation("System.Reset");
}
public void BuzzerOff()
{
InvokeClient.Instance.Service.DoOperation($"PM1.SignalTower.{AITSignalTowerOperation.SwitchOffBuzzer}",true);
}
#region override functions
public override void CanClose(Action<bool> callback)
{
if (BaseApp.Instance.UserMode == UserMode.Normal)
{
callback(false);
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (ThreadStart)delegate
{
OnLogoutCommand();
});
}
else
callback(true);
}
protected override void OnInitialize()
{
//display system version or other info...
DisplayName = "Sic";
base.OnInitialize();
StartTimer();
}
protected override void OnActivate()
{
base.OnActivate();
ShowAllEvents();
EnableTimer(true);
}
private void DrawSciChart()
{
// Create the chart surface
var sciChartSurface = new SciChartSurface();
// Create the X and Y Axis
var xAxis = new NumericAxis() { AxisTitle = "Number of Samples (per series)" };
var yAxis = new NumericAxis() { AxisTitle = "Value" };
sciChartSurface.XAxis = xAxis;
sciChartSurface.YAxis = yAxis;
// Specify Interactivity Modifiers
sciChartSurface.ChartModifier = new ModifierGroup(new RubberBandXyZoomModifier(), new ZoomExtentsModifier());
// Add annotation hints to the user
var textAnnotation = new TextAnnotation()
{
Text = "Hello World!",
X1 = 5.0,
Y1 = 5.0
};
sciChartSurface.Annotations.Add(textAnnotation);
}
protected override void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
_view = view as MainView;
_view.tbLoginName.Focus();
_view.SplashScreen?.Complete();
}
protected override void OnDeactivate(bool close)
{
base.OnDeactivate(close);
EnableTimer(false);
}
#endregion
#region
#region Sync ShutDown Thread
public delegate void ShutDownSysncThread();
private ShutDownSysncThread _shutdownThread = null;
private ShutdownViewModel _shutdownWindow = null;
private void ShutdownExecute()
{
BaseApp.Instance.UserMode = UserMode.Shutdown;
BaseApp.Instance.UserContext.IsLogin = false;
LOG.Info(string.Format("{0} shutdown as {1}", BaseApp.Instance.UserContext.LoginName, BaseApp.Instance.UserContext.RoleName));
TryClose();
}
private void ShutdownCallBack(IAsyncResult result)
{
if (_shutdownWindow != null)
{
_shutdownWindow.TryClose();
}
_shutdownThread.EndInvoke(result);
}
#endregion
#region Menu Control and page switch
private void InitMenu()
{
MenuItems = BaseApp.Instance.MenuManager.MenuItems;
SubMenuItems = new List<AppMenu>();
HistoryMenus = new ObservableCollection<AppMenu>();
if (MenuItems.Count > 0)
{
AppMenu @default = null;
foreach (AppMenu menuitem in MenuItems)
{
if (menuitem.MenuItems.Count > 0)
{
if (menuitem.AlarmModule == nameof(System))
{
_alarmMenu = menuitem;
break;
}
if (@default == null)
@default = menuitem.MenuItems[0];
}
}
SwitchMenuItem(@default);
}
}
public void MainSwitchMenuItem(AppMenu menuViewItem)
{
if (menuViewItem.MenuItems.Count > 0)
{
if (menuViewItem.LastSelectedSubMenu != null)
SwitchMenuItem(menuViewItem.LastSelectedSubMenu);
else
SwitchMenuItem(menuViewItem.MenuItems[0]);
}
}
public void SwitchMenuItem(AppMenu menuViewItem)
{
if (menuViewItem.ViewModel != null && menuViewItem.ViewModel != string.Empty)
{
if (menuViewItem.Model == null)
{
menuViewItem.Model = (BaseModel)AssemblyUtil.CreateInstance(AssemblyUtil.GetType(menuViewItem.ViewModel));
((BaseModel)menuViewItem.Model).Permission = menuViewItem.Permission;
((BaseModel)menuViewItem.Model).Token = BaseApp.Instance.UserContext.Token;
if (menuViewItem.Model is ISupportMultipleSystem)
(menuViewItem.Model as ISupportMultipleSystem).SystemName = menuViewItem.System;
}
ActivateItem(((BaseModel)menuViewItem.Model));
CurrentViewModel = ((BaseModel)menuViewItem.Model);
//if (((BaseModel)menuViewItem.Model).Page != PageID.MAX_PAGE)
// BaseApp.Instance.SetCurrentPage(((BaseModel)menuViewItem.Model).Page);
HandleSubAndHistoryMenu(menuViewItem);
if (_currentMenuItem != null)
{
_currentMenuItem.Selected = false;
_currentMenuItem.Parent.Selected = false;
}
menuViewItem.Selected = true;
menuViewItem.Parent.Selected = true;
menuViewItem.Parent.LastSelectedSubMenu = menuViewItem;
_currentMenuItem = menuViewItem;
}
}
private void HandleSubAndHistoryMenu(AppMenu menuitem)
{
SubMenuItems = menuitem.Parent.MenuItems;
if (!HistoryMenus.Contains(menuitem))
{
if (HistoryMenus.Count >= 8)
HistoryMenus.RemoveAt(7);
HistoryMenus.Insert(0, menuitem);
}
else
{
HistoryMenus.Remove(menuitem);
HistoryMenus.Insert(0, menuitem);
}
}
public bool SwitchPage(string firstLevelMenuId, string secondLevelMenuId)
{
foreach (AppMenu menuitem in BaseApp.Instance.MenuManager.MenuItems)
{
if (menuitem.MenuID == firstLevelMenuId)
{
foreach (AppMenu menu in menuitem.MenuItems)
{
if (menu.MenuID == secondLevelMenuId)
{
SwitchMenuItem(menu);
return true;
}
}
}
}
return false;
}
#endregion
#region Refresh Date Time on page
protected override void InvokeAfterUpdateProperty(Dictionary<string, object> data)
{
}
protected override bool OnTimer()
{
try
{
base.Poll();
}
catch (Exception ex)
{
LOG.Error(ex.Message);
}
return true;
}
private void StartTimer()
{
var myDispatcherTimer =
new DispatcherTimer();
myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000);
myDispatcherTimer.Tick += new EventHandler(Each_Tick);
myDispatcherTimer.Start();
}
public void Each_Tick(object o, EventArgs sender)
{
NowDateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
NotifyOfPropertyChange(nameof(NowDateTime));
}
#endregion
#endregion
}
}