添加项目文件。

This commit is contained in:
czj
2026-06-05 10:57:09 +08:00
parent f29671b374
commit d960cb5912
166 changed files with 15996 additions and 0 deletions

24
ADP/ADP.csproj Normal file
View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Command\Command.csproj" />
<ProjectReference Include="..\DeviceCommand\DeviceCommand.csproj" />
<ProjectReference Include="..\LoginModule\LoginModule.csproj" />
<ProjectReference Include="..\MainModule\MainModule.csproj" />
<ProjectReference Include="..\MonitorModule\MonitorModule.csproj" />
<ProjectReference Include="..\Service\Service.csproj" />
<ProjectReference Include="..\SettingModule\SettingModule.csproj" />
<ProjectReference Include="..\TestingModule\TestingModule.csproj" />
<ProjectReference Include="..\UIShare\UIShare.csproj" />
<ProjectReference Include="..\UpdateInfoMoudle\UpdateInfoMoudle.csproj" />
</ItemGroup>
</Project>

15
ADP/App.xaml Normal file
View File

@@ -0,0 +1,15 @@
<prism:PrismApplication x:Class="ADP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ADP"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--自定义style-->
<ResourceDictionary Source="/UIShare;component/Styles/CommonStyle.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</prism:PrismApplication>

88
ADP/App.xaml.cs Normal file
View File

@@ -0,0 +1,88 @@
using Common;
using ADP.ViewModels;
using ADP.ViewModels.Dialogs;
using ADP.Views;
using ADP.Views;
using ADP.Views.Dialogs;
using Logger;
using Notifications.Wpf.Core;
using ORM;
using Service.Implement;
using Service.Interface;
using System.Configuration;
using System.Data;
using System.Reflection;
using System.Windows;
using UIShare.PubEvent;
using static System.Runtime.InteropServices.JavaScript.JSType;
using UIShare.GlobalVariable;
using UIShare;
namespace ADP
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
//UI线程未捕获异常处理事件
this.DispatcherUnhandledException += OnDispatcherUnhandledException;
//Task线程内未捕获异常处理事件
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
////多线程异常
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
return Container.Resolve<ShellView>();
}
private void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
LoggerHelper.Error(e.Exception.Message, e.Exception.StackTrace);
}
private void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
LoggerHelper.Error(e.Exception.Message, e.Exception.StackTrace);
}
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
//记录dump文件
Exception ex = e.ExceptionObject as Exception;
MiniDump.TryDump($"dumps\\Error_{DateTime.Now:yyyy-MM-dd HH-mm-ss-ms}.dmp", MiniDump.Option.WithFullMemory, ex);
}
protected override void OnInitialized()
{
//初始化数据库
//DatabaseConfig.SetTenant(10001);
//DatabaseConfig.InitMySql("127.0.0.1",3306,"ADP","root","123456");
//DatabaseConfig.CreateDatabaseAndCheckConnection(createDatabase: true, checkConnection: true);
//SqlSugarContext.InitDatabase();
//显示登录窗口
var login = Container.Resolve<LoginModuleView>();
var re = Container.Resolve<IRegionManager>();
RegionManager.SetRegionManager(login, re);
RegionManager.SetRegionManager(Application.Current.MainWindow, re);
login.Show();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//注册弹窗
containerRegistry.RegisterDialog<MessageBoxView, MessageBoxViewModel>("MessageBox");
// 注册通知管理器
INotificationManager NotificationManager = new NotificationManager();
containerRegistry.RegisterInstance<INotificationManager>(NotificationManager);
//注册全局变量
containerRegistry.RegisterScoped<SystemConfig>();
containerRegistry.RegisterScoped<StepRunning>();
containerRegistry.RegisterScoped<ScopedContext>();
containerRegistry.RegisterSingleton<GlobalInfo>();
}
//指定模块加载方式(需要手动将模块生成的dll放入Modules文件夹中)
protected override IModuleCatalog CreateModuleCatalog()
{
//指定模块加载方式为从文件夹中以反射发现并加载module(推荐用法)
return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
}
}
}

10
ADP/AssemblyInfo.cs Normal file
View File

@@ -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)
)]

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,120 @@
using UIShare.PubEvent;
using UIShare.ViewModelBase;
using System.Windows.Input;
namespace ADP.ViewModels.Dialogs
{
public class MessageBoxViewModel : DialogViewModelBase
{
#region
private string _Title;
public string Title
{
get => _Title;
set => SetProperty(ref _Title, value);
}
private string _Message = "";
public string Message
{
get => _Message;
set => SetProperty(ref _Message, value);
}
private string _Icon= $"pack://siteoforigin:,,,/Resources/Images/info.png";
public string Icon
{
get => _Icon;
set => SetProperty(ref _Icon, value);
}
private bool _ShowYes;
public bool ShowYes
{
get => _ShowYes;
set => SetProperty(ref _ShowYes, value);
}
private bool _ShowNo;
public bool ShowNo
{
get => _ShowNo;
set => SetProperty(ref _ShowNo, value);
}
private bool _ShowOk;
public bool ShowOk
{
get => _ShowOk;
set => SetProperty(ref _ShowOk, value);
}
private bool _ShowCancel;
public bool ShowCancel
{
get => _ShowCancel;
set => SetProperty(ref _ShowCancel, value);
}
#endregion
#region
public ICommand YesCommand { get; set; }
public ICommand NoCommand { get; set; }
public ICommand OkCommand { get; set; }
public ICommand CancelCommand { get; set; }
#endregion
public DialogCloseListener RequestClose { get; set; }
public MessageBoxViewModel(IContainerProvider containerProvider):base(containerProvider)
{
YesCommand = new DelegateCommand(OnYes);
NoCommand = new DelegateCommand(OnNo);
OkCommand = new DelegateCommand(OnOk);
CancelCommand = new DelegateCommand(OnCancel);
}
private void CloseDialog(ButtonResult result)
{
var parameters = new DialogParameters();
RequestClose.Invoke(new DialogResult(result));
}
private void OnYes() => CloseDialog(ButtonResult.Yes);
private void OnNo() => CloseDialog(ButtonResult.No);
private void OnOk() => CloseDialog(ButtonResult.OK);
private void OnCancel() => CloseDialog(ButtonResult.Cancel);
#region Prism Dialog
public bool CanCloseDialog() => true;
public override void OnDialogClosed()
{
_eventAggregator.GetEvent<OverlayEvent>().Publish(false);
}
public override void OnDialogOpened(IDialogParameters parameters)
{
_eventAggregator.GetEvent<OverlayEvent>().Publish(true);
Title = parameters.GetValue<string>("Title");
Message = parameters.GetValue<string>("Message");
var iconKey = parameters.GetValue<string>("Icon"); // info / error / warn
Icon = iconKey switch
{
"info" => $"pack://siteoforigin:,,,/Resources/Images/info.png",
"error" => $"pack://siteoforigin:,,,/Resources/Images/error.png",
"warn" => $"pack://siteoforigin:,,,/Resources/Images/warning.png",
_ => $"pack://siteoforigin:,,,/Resources/Images/info.png" // 默认
};
ShowYes = parameters.GetValue<bool>("ShowYes");
ShowNo = parameters.GetValue<bool>("ShowNo");
ShowOk = parameters.GetValue<bool>("ShowOk");
ShowCancel = parameters.GetValue<bool>("ShowCancel");
}
#endregion
}
}

View File

@@ -0,0 +1,772 @@
using Logger;
using MaterialDesignThemes.Wpf;
using Notifications.Wpf.Core;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading; // 💡 新增:引入定时器命名空间
using UIShare;
using UIShare.GlobalVariable;
using UIShare.PubEvent;
using UIShare.UIViewModel;
namespace ADP.ViewModels
{
public class ShellViewModel : BindableBase
{
#region
private string _Title = "";
private bool _IsLeftDrawerOpen;
private readonly ConcurrentDictionary<string, Task> _executionTasks = new();
private readonly ConcurrentDictionary<string, Task> _errorExecutionTasks = new();
private readonly IEventAggregator _eventAggregator;
private readonly IRegionManager _regionManager;
private readonly IContainerProvider _containerProvider;
private readonly INotificationManager _notificationManager;
private readonly IModuleManager _moduleManager;
private readonly GlobalInfo _globalInfo;
// 💡 新增UI 刷新定时器,用于高频让前端重新拉取当前工位的 SW 累计时间
private readonly DispatcherTimer _uiRefreshTimer;
#endregion
#region
public string Title
{
get => _Title;
set => SetProperty(ref _Title, value);
}
public bool IsLeftDrawerOpen
{
get => _IsLeftDrawerOpen;
set => SetProperty(ref _IsLeftDrawerOpen, value);
}
// 代理属性:动态反映当前被激活的 Scope 状态
public TimeSpan RunningTime
{
get
{
if (CurrentContext == null) return TimeSpan.Zero;
// 💡 核心:如果当前工位的计时器正在跑,动态累加 SW 当前的时间,否则返回其保存的固定时间值
return CurrentContext.SW.IsRunning ? CurrentContext.SW.Elapsed : CurrentContext.RunningTime;
}
set
{
if (CurrentContext != null && CurrentContext.RunningTime != value)
{
CurrentContext.RunningTime = value;
RaisePropertyChanged();
}
}
}
public bool IsTerminate
{
get => CurrentContext?.IsTerminate ?? false;
set
{
if (CurrentContext != null && CurrentContext.IsTerminate != value)
{
CurrentContext.IsTerminate = value;
RaisePropertyChanged();
}
}
}
private ScopedContext? CurrentContext =>
_globalInfo.ContextDic.TryGetValue(_globalInfo.CurrentScope, out var ctx) ? ctx : null;
private StepRunning? CurrentRunner =>
_globalInfo.StepRunningDic.TryGetValue(_globalInfo.CurrentScope, out var runner) ? runner : null;
public string RunState
{
get => CurrentContext?.RunState ?? "运行";
set
{
if (CurrentContext != null && CurrentContext.RunState != value)
{
CurrentContext.RunState = value;
RaisePropertyChanged();
}
}
}
public bool SingleStep
{
get => CurrentContext?.SingleStep ?? false;
set
{
if (CurrentContext != null && CurrentContext.SingleStep != value)
{
CurrentContext.SingleStep = value;
RaisePropertyChanged();
}
}
}
public PackIconKind RunIcon
{
get => CurrentContext?.RunIcon ?? PackIconKind.Play;
set
{
if (CurrentContext != null && CurrentContext.RunIcon != value)
{
CurrentContext.RunIcon = value;
RaisePropertyChanged();
}
}
}
#endregion
#region
public ICommand LeftDrawerOpenCommand { get; set; }
public ICommand MinimizeCommand { get; set; }
public ICommand MaximizeCommand { get; set; }
public ICommand CloseCommand { get; set; }
public ICommand NavigateCommand { get; set; }
public ICommand LoadCommand { get; set; }
public ICommand RefreshCommand { get; set; }
public ICommand DestroyCommand { get; set; }
public ICommand RunningCommand { get; set; }
public ICommand RunSingleCommand { get; set; }
public ICommand RestorationCommand { get; set; }
public ICommand RunAbnormalStepsCommand { get; set; }
public ICommand SaveAsCommand { get; set; }
public ICommand SaveCommand { get; set; }
public ICommand OpenCommand { get; set; }
public ICommand NewCommand { get; set; }
public ICommand SetDefaultCommand { get; set; }
#endregion
public ShellViewModel(IContainerProvider containerProvider)
{
_containerProvider = containerProvider;
_globalInfo = containerProvider.Resolve<GlobalInfo>();
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
_regionManager = containerProvider.Resolve<IRegionManager>();
_notificationManager = containerProvider.Resolve<INotificationManager>();
_moduleManager = containerProvider.Resolve<IModuleManager>();
LeftDrawerOpenCommand = new DelegateCommand(LeftDrawerOpen);
MinimizeCommand = new DelegateCommand<Window>(MinimizeWindow);
MaximizeCommand = new DelegateCommand<Window>(MaximizeWindow);
CloseCommand = new DelegateCommand<Window>(CloseWindow);
NavigateCommand = new DelegateCommand<string>(Navigate);
LoadCommand = new DelegateCommand(Load);
RefreshCommand = new DelegateCommand(OnRefresh);
DestroyCommand = new DelegateCommand(OnDestroy);
RunningCommand = new DelegateCommand(OnRunning);
RunSingleCommand = new DelegateCommand(RunSingle);
RestorationCommand = new AsyncDelegateCommand(OnRestoration);
RunAbnormalStepsCommand = new AsyncDelegateCommand(OnRunAbnormalSteps);
NewCommand = new DelegateCommand(New);
OpenCommand = new AsyncDelegateCommand<string>(Open);
SaveAsCommand = new DelegateCommand(SaveAs);
SaveCommand = new DelegateCommand(Save);
SetDefaultCommand = new DelegateCommand(SetDefault);
_globalInfo.ContextDic.Add("default", new ScopedContext());
_eventAggregator.GetEvent<LoginSuccessEvent>().Subscribe(() =>
{
Application.Current.MainWindow.Show();
_regionManager.RequestNavigate("ShellViewManager", "MainView");
});
_eventAggregator.GetEvent<RunSingalCompletedEvent>().Subscribe(UpdateRunIcon);
_globalInfo.ScopeChanged += (s, e) =>
{
RefreshAllContextProperties();
};
// 💡 初始化轻量级 UI 定时器:每 100 毫秒刷新一次当前可见工位的界面时间
_uiRefreshTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100) };
_uiRefreshTimer.Tick += (s, e) => RaisePropertyChanged(nameof(RunningTime));
_uiRefreshTimer.Start();
}
private void RefreshAllContextProperties()
{
RaisePropertyChanged(nameof(RunState));
RaisePropertyChanged(nameof(SingleStep));
RaisePropertyChanged(nameof(RunIcon));
RaisePropertyChanged(nameof(RunningTime));
RaisePropertyChanged(nameof(IsTerminate));
}
#region
private async void OnRunning()
{
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
StepRunning? targetRunner = CurrentRunner;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null || targetRunner == null)
{
return;
}
if (targetContext.RunState == "运行")
{
targetContext.SingleStep = false;
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 运行命令");
targetContext.RunState = "暂停";
targetContext.RunIcon = PackIconKind.Pause;
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
if (targetContext.IsStop == null)
{
targetContext.IsStop = false;
// 💡 启动或恢复:启动属于该快照工位独立的 SW 计时器
targetContext.SW.Start();
if (!_executionTasks.TryGetValue(runningScope, out var existingTask) || existingTask == null)
{
existingTask = targetRunner.ExecuteSteps(targetContext.Program, cancellationToken: targetRunner.stepCTS.Token);
_executionTasks[runningScope] = existingTask;
}
try
{
await existingTask;
}
catch (Exception ex)
{
LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 异常中止: {ex.Message}");
}
// 💡 测试正常完毕或取消:停止当前工位的 SW并将最终时间固化到 RunningTime 字段中
targetContext.SW.Stop();
targetContext.RunningTime = targetContext.SW.Elapsed;
targetContext.RunState = "运行";
targetContext.RunIcon = PackIconKind.Play;
targetContext.IsStop = null;
if (targetRunner.stepCTS.IsCancellationRequested)
{
targetRunner.stepCTS = new CancellationTokenSource();
_executionTasks.TryRemove(runningScope, out _);
}
else if (_executionTasks.TryGetValue(runningScope, out var currentTask) && currentTask != null && currentTask.IsCompleted)
{
targetContext.IsTerminate = true;
_executionTasks.TryRemove(runningScope, out _);
}
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
}
else if (targetContext.IsStop == true)
{
targetContext.IsStop = false;
// 💡 从暂停中恢复,继续累加当前工位计时
targetContext.SW.Start();
}
}
else // 用户点击了暂停
{
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 点击工位 [{runningScope}] 暂停命令");
targetContext.SingleStep = true;
targetContext.IsStop = true;
targetContext.RunState = "运行";
targetContext.RunIcon = PackIconKind.Play;
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
}
}
private async void RunSingle()
{
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
StepRunning? targetRunner = CurrentRunner;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null || targetRunner == null)
{
return;
}
if (targetContext.RunState == "运行")
{
targetContext.SingleStep = true;
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 单步执行命令");
targetContext.RunState = "暂停";
targetContext.RunIcon = PackIconKind.Pause;
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
if (targetContext.IsStop == null)
{
targetContext.IsStop = false;
// 💡 单步启动:让专属工位的 SW 跑起来
targetContext.SW.Start();
if (!_executionTasks.TryGetValue(runningScope, out var existingTask) || existingTask == null)
{
existingTask = targetRunner.ExecuteSteps(targetContext.Program, cancellationToken: targetRunner.stepCTS.Token);
_executionTasks[runningScope] = existingTask;
}
try
{
await existingTask;
}
catch (Exception ex)
{
LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 单步执行异常: {ex.Message}");
}
// 💡 单步单步完成后会被 StepRunning 挂起,在此暂时停止 SW
targetContext.SW.Stop();
targetContext.RunningTime = targetContext.SW.Elapsed;
targetContext.RunState = "运行";
targetContext.RunIcon = PackIconKind.Play;
targetContext.IsStop = null;
if (targetRunner.stepCTS.IsCancellationRequested)
{
targetRunner.stepCTS = new CancellationTokenSource();
_executionTasks.TryRemove(runningScope, out _);
}
else if (_executionTasks.TryGetValue(runningScope, out var currentTask) && currentTask != null && currentTask.IsCompleted)
{
targetContext.IsTerminate = true;
_executionTasks.TryRemove(runningScope, out _);
}
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
}
else if (targetContext.IsStop == true)
{
targetContext.IsStop = false;
// 💡 继续单步,继续计时
targetContext.SW.Start();
}
}
}
private async Task OnRestoration()
{
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
StepRunning? targetRunner = CurrentRunner;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null || targetRunner == null)
{
return;
}
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 复位命令");
_executionTasks.TryGetValue(runningScope, out var currentTask);
_errorExecutionTasks.TryGetValue(runningScope, out var errorTask);
if (currentTask != null || errorTask != null)
{
targetRunner.stepCTS.Cancel();
targetRunner.errorStepCTS.Cancel();
await Task.Delay(200);
// 💡 彻底复位停止当前工位的计时器并且完全归零Reset
targetContext.SW.Reset();
targetContext.RunningTime = TimeSpan.Zero;
targetContext.IsStop = null;
targetRunner.ResetAllStepStatus(targetContext.Program.StepCollection);
targetRunner.ResetAllStepStatus(targetContext.Program.ErrorStepCollection);
targetContext.IsTerminate = false;
}
else
{
targetRunner.stepCTS = new CancellationTokenSource();
targetRunner.errorStepCTS = new CancellationTokenSource();
// 💡 无任务状态下的直接归零
targetContext.SW.Reset();
targetContext.RunningTime = TimeSpan.Zero;
targetContext.IsStop = null;
targetRunner.ResetAllStepStatus(targetContext.Program.StepCollection);
targetRunner.ResetAllStepStatus(targetContext.Program.ErrorStepCollection);
targetContext.IsTerminate = false;
}
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
}
private async Task OnRunAbnormalSteps()
{
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
StepRunning? targetRunner = CurrentRunner;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null || targetRunner == null)
{
return;
}
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 异常流程命令");
// 💡 异常测试启动计时
targetContext.SW.Start();
if (!_errorExecutionTasks.TryGetValue(runningScope, out var existingErrorTask) || existingErrorTask == null)
{
existingErrorTask = targetRunner.ExecuteErrorSteps(targetContext.Program, cancellationToken: targetRunner.errorStepCTS.Token);
_errorExecutionTasks[runningScope] = existingErrorTask;
}
try
{
await existingErrorTask;
}
catch (Exception ex)
{
LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 异常流程执行出错: {ex.Message}");
}
// 💡 异常测试结束停止计时
targetContext.SW.Stop();
targetContext.RunningTime = targetContext.SW.Elapsed;
if (targetRunner.errorStepCTS.IsCancellationRequested)
{
targetRunner.errorStepCTS = new CancellationTokenSource();
_errorExecutionTasks.TryRemove(runningScope, out _);
}
else if (_errorExecutionTasks.TryGetValue(runningScope, out var currentErrorTask) && currentErrorTask != null && currentErrorTask.IsCompleted)
{
targetContext.IsTerminate = true;
_errorExecutionTasks.TryRemove(runningScope, out _);
}
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
}
private void SetDefault()
{
// 💡 1. 抓取触发瞬间的 Scope 与 Context 快照
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null) return;
if (targetContext.CurrentFilePath != null)
{
//SystemConfig.DefaultProgramFilePath = targetContext.CurrentFilePath;
//ConfigService.Save();
LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 已成功将当前程序设为默认启动程序");
}
}
private void New()
{
// 💡 1. 抓取快照
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null) return;
// 💡 2. 严格对快照隔离的 Context 数据进行清理,不影响其他工位
targetContext.CurrentFilePath = null;
targetContext.Program.Parameters.Clear();
targetContext.Program.StepCollection.Clear();
targetContext.Program.ErrorStepCollection.Clear();
LoggerHelper.InfoWithNotify($"工位 [{runningScope}] 创建了空程序文件");
// 如果当前正看着该工位,刷新 UI 显示
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
}
private async Task Open(string filePath = null)
{
// 💡 1. 抓取进方法瞬间的快照,锁死上下文
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null) return;
try
{
// 如果没有传路径弹出文件选择对话框WPF 对话框是模态的,会阻塞当前 UI 线程)
if (string.IsNullOrEmpty(filePath))
{
var openFileDialog = new Microsoft.Win32.OpenFileDialog
{
Filter = "ADP程序文件|*.ADP|所有文件|*.*",
Title = $"工位 [{runningScope}] 打开程序",
};
if (openFileDialog.ShowDialog() != true)
return; // 用户取消选择
filePath = openFileDialog.FileName;
}
// 确认文件存在
if (!File.Exists(filePath))
{
LoggerHelper.ErrorWithNotify($"文件不存在: {filePath}");
return;
}
// 读取 JSON 文件
string json = File.ReadAllText(filePath);
// 反序列化为 ProgramModel
var program = Newtonsoft.Json.JsonConvert.DeserializeObject<ProgramModel>(json);
if (program == null)
{
LoggerHelper.WarnWithNotify($"文件格式不正确或为空: {filePath}");
return;
}
// 💡 2. 严格赋值给快照锁定下的当前工位上下文,实现数据完全隔离
targetContext.Program.Parameters = program.Parameters;
targetContext.Program.StepCollection = program.StepCollection;
targetContext.Program.ErrorStepCollection = program.ErrorStepCollection;
targetContext.CurrentFilePath = filePath;
LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 成功打开文件: {filePath}");
// 💡 3. 安全调用异步复位,确保重置的是对应工位的数据
// 注意:由于在 OnRestoration 内部第一行也做了快照拦截,
// 如果用户此时正好在看这个工位,它会自动完美执行
await OnRestoration();
}
catch (Exception ex)
{
LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 打开文件失败: {ex.Message}");
}
finally
{
// 💡 4. 异步回归:不管中途用户切去了哪里,回到该工位时及时刷新显示
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
}
}
private void SaveAs()
{
if (!_globalInfo.IsAdmin) return;
// 💡 1. 抓取快照
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null) return;
string defaultPath = @"D:\ADP\子程序";
if (!Directory.Exists(defaultPath))
Directory.CreateDirectory(defaultPath);
var saveFileDialog = new Microsoft.Win32.SaveFileDialog
{
Filter = "ADP程序文件|*.adp|所有文件|*.*",
Title = $"工位 [{runningScope}] 程序另存为",
FileName = "NewProgram.ADP",
InitialDirectory = defaultPath
};
if (saveFileDialog.ShowDialog() == true)
{
// 💡 2. 将新路径安全写入快照工位
targetContext.CurrentFilePath = saveFileDialog.FileName;
// 💡 3. 调用你的底层文件保存逻辑,传入快照工位的 Program 模型
SaveProgramToFile(targetContext.CurrentFilePath, targetContext.Program);
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 另存为文件成功: {saveFileDialog.FileName}");
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
}
}
private void Save()
{
if (!_globalInfo.IsAdmin) return;
// 💡 1. 抓取快照
string runningScope = _globalInfo.CurrentScope;
ScopedContext? targetContext = CurrentContext;
if (runningScope == "default" || string.IsNullOrEmpty(runningScope) || targetContext == null) return;
// 💡 2. 判断当前工位是否有历史路径
if (targetContext.CurrentFilePath == null)
{
SaveAs();
return;
}
// 💡 3. 持久化当前快照工位的 Program
SaveProgramToFile(targetContext.CurrentFilePath, targetContext.Program);
LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 程序保存成功!");
}
// 💡 辅助方法:建议将你的通用序列化落盘代码调整为接收 ProgramModel 参数,提高复用性
private void SaveProgramToFile(string filePath, ProgramModel programModel)
{
try
{
string json = Newtonsoft.Json.JsonConvert.SerializeObject(programModel, Newtonsoft.Json.Formatting.Indented);
File.WriteAllText(filePath, json);
}
catch (Exception ex)
{
LoggerHelper.ErrorWithNotify($"写入程序文件失败: {ex.Message}");
}
}
private void UpdateRunIcon(string obj)
{
CurrentContext?.SW.Stop();
CurrentContext.RunningTime = CurrentContext.SW.Elapsed;
RunIcon = obj switch
{
"Play" => PackIconKind.Play,
"Pause" => PackIconKind.Pause,
_ => RunIcon
};
}
private void OnRefresh()
{
_eventAggregator.GetEvent<ExpandViewEvent>().Publish("");
_globalInfo.CurrentScope = "default";
}
private void OnDestroy()
{
if (_globalInfo.CurrentScope == "default" || string.IsNullOrEmpty(_globalInfo.CurrentScope)) return;
string targetRegionName = _globalInfo.CurrentScope;
// 💡 物理销毁工位时,顺便清理任务字典,防止内存泄漏
_executionTasks.TryRemove(targetRegionName, out _);
_errorExecutionTasks.TryRemove(targetRegionName, out _);
if (_regionManager.Regions.ContainsRegionWithName(targetRegionName))
{
var region = _regionManager.Regions[targetRegionName];
var viewsToDestroy = region.Views.ToList();
foreach (var view in viewsToDestroy)
{
if (view is FrameworkElement element)
{
var viewModel = element.DataContext;
region.Remove(view);
if (viewModel is IDisposable disposableVM) disposableVM.Dispose();
}
}
}
_globalInfo.ContextDic.Remove(targetRegionName);
_globalInfo.StepRunningDic.Remove(targetRegionName);
var parameters = new NavigationParameters { { "Name", targetRegionName } };
_regionManager.RequestNavigate(targetRegionName, "ProtocolStartView", parameters);
_eventAggregator.GetEvent<ExpandViewEvent>().Publish("");
}
private void Load()
{
_notificationManager.ShowAsync(new NotificationContent { Title = "登录成功", Message = "", Type = NotificationType.Success });
//默认导航到主界面
Type moduleAType = typeof(MainModule.MainModule);
_moduleManager.LoadModule(moduleAType.Name);
}
private void Navigate(string content)
{
switch (content)
{
case "主界面":
if (_globalInfo.CurrentScope == "default" || string.IsNullOrEmpty(_globalInfo.CurrentScope))
{
_regionManager.RequestNavigate("ShellViewManager", "MainView");
break;
}
var TestingRegion = _globalInfo.CurrentScope;
if (!_regionManager.Regions.ContainsRegionWithName(TestingRegion)) break;
_regionManager.RequestNavigate(TestingRegion, "AutomatedTestingView");
break;
case "监控界面":
// 仅当某个工位被选中(九宫格已展开/选择)时才跳转,默认 default 跳过。
if (_globalInfo.CurrentScope == "default" || string.IsNullOrEmpty(_globalInfo.CurrentScope)) break;
// 记录界面不是填到全局的 ShellViewManager而是填到该工位专属的 region。
var monitorRegion = _globalInfo.CurrentScope;
if (!_regionManager.Regions.ContainsRegionWithName(monitorRegion)) break;
var monitorParameters = new NavigationParameters { { "Name", monitorRegion } };
_regionManager.RequestNavigate(monitorRegion, "MonitorView", monitorParameters);
IsLeftDrawerOpen = false;
break;
case "记录界面":
if (_globalInfo.CurrentScope == "default" || string.IsNullOrEmpty(_globalInfo.CurrentScope)) break;
// 记录界面不是填到全局的 ShellViewManager而是填到该工位专属的 region。
var recordRegion = _globalInfo.CurrentScope;
if (!_regionManager.Regions.ContainsRegionWithName(recordRegion)) break;
var recordParameters = new NavigationParameters { { "Name", recordRegion } };
_regionManager.RequestNavigate(recordRegion, "RecordView", recordParameters);
IsLeftDrawerOpen = false;
break;
case "设置界面":
if (_globalInfo.CurrentScope == "default" || string.IsNullOrEmpty(_globalInfo.CurrentScope)) break;
// 记录界面不是填到全局的 ShellViewManager而是填到该工位专属的 region。
var settingRegion = _globalInfo.CurrentScope;
if (!_regionManager.Regions.ContainsRegionWithName(settingRegion)) break;
var settingParameters = new NavigationParameters { { "Name", settingRegion } };
_regionManager.RequestNavigate(settingRegion, "SettingView", settingParameters);
IsLeftDrawerOpen = false;
break;
case "更新界面":
_regionManager.RequestNavigate("ShellViewManager", "UpdateInfoView");
break;
}
}
private void LeftDrawerOpen()
{
IsLeftDrawerOpen = true;
}
private void MinimizeWindow(Window window)
{
if (window != null)
window.WindowState = WindowState.Minimized;
}
private void MaximizeWindow(Window window)
{
if (window != null)
{
window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}
}
private void CloseWindow(Window window)
{
window?.Close();
}
#endregion
}
}

View File

@@ -0,0 +1,87 @@
<UserControl x:Class="ADP.Views.Dialogs.MessageBoxView"
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:ADP.Views.Dialogs"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
xmlns:prism="http://prismlibrary.com/"
Background="Transparent"
prism:ViewModelLocator.AutoWireViewModel="True"
Height="250"
Width="300">
<prism:Dialog.WindowStyle>
<Style BasedOn="{StaticResource DialogUserManageStyle}"
TargetType="Window" />
</prism:Dialog.WindowStyle>
<Border CornerRadius="20"
Background="white"
MouseLeftButtonDown="Border_MouseLeftButtonDown">
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Title -->
<TextBlock Grid.Row="0"
Margin="15 5 5 5"
FontSize="18"
FontWeight="Bold"
VerticalAlignment="Center"
Text="{Binding Title}"
Foreground="#333" />
<StackPanel HorizontalAlignment="Center"
Grid.Row="1">
<!-- Icon -->
<Image
Width="100"
Height="100"
VerticalAlignment="Top"
Margin="5 15 0 0"
Source="{Binding Icon}" />
<!-- Message -->
<TextBlock
FontSize="20"
Margin="15 0 0 0"
TextAlignment="Center"
TextWrapping="Wrap"
Text="{Binding Message}" />
</StackPanel>
<!-- Buttons -->
<StackPanel Grid.Row="2"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="Yes"
Width="80"
Margin="10 10"
Visibility="{Binding ShowYes, Converter={StaticResource BooleanToVisibilityConverter}}"
Command="{Binding YesCommand}" />
<Button Content="No"
Width="80"
Margin="10 10"
Visibility="{Binding ShowNo, Converter={StaticResource BooleanToVisibilityConverter}}"
Command="{Binding NoCommand}" />
<Button Content="OK"
Width="80"
Margin="10 10"
Visibility="{Binding ShowOk, Converter={StaticResource BooleanToVisibilityConverter}}"
Command="{Binding OkCommand}" />
<Button Content="Cancel"
Width="80"
Margin="10 10"
Visibility="{Binding ShowCancel, Converter={StaticResource BooleanToVisibilityConverter}}"
Command="{Binding CancelCommand}" />
</StackPanel>
</Grid>
</Border>
</UserControl>

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ADP.Views.Dialogs
{
/// <summary>
/// MessageBoxView.xaml 的交互逻辑
/// </summary>
public partial class MessageBoxView : UserControl
{
public MessageBoxView()
{
InitializeComponent();
}
private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Window.GetWindow(this)?.DragMove();
}
}
}
}

View File

@@ -0,0 +1,21 @@
<mah:MetroWindow xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:helpers="clr-namespace:UIShare.Helpers;assembly=UIShare"
x:Class="ADP.Views.LoginModuleView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:ADP.Views"
mc:Ignorable="d"
Title="ADP"
WindowStartupLocation="CenterScreen"
Height="315"
Width="420"
ResizeMode="NoResize">
<Grid>
<ContentControl prism:RegionManager.RegionName="LoginRegion" />
</Grid>
</mah:MetroWindow>

View File

@@ -0,0 +1,38 @@
using UIShare.PubEvent;
using MahApps.Metro.Controls;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Path = System.IO.Path;
namespace ADP.Views
{
/// <summary>
/// Login.xaml 的交互逻辑
/// </summary>
public partial class LoginModuleView : MetroWindow
{
public LoginModuleView(IEventAggregator eventAggregator)
{
InitializeComponent();
//订阅登录成功事件
eventAggregator.GetEvent<LoginSuccessEvent>().Subscribe(() =>
{
this.Close();
});
}
}
}

339
ADP/Views/ShellView.xaml Normal file
View File

@@ -0,0 +1,339 @@
<Window x:Class="ADP.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:converter="clr-namespace:UIShare.Converters;assembly=UIShare"
xmlns:prism="http://prismlibrary.com/"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
WindowStartupLocation="CenterScreen"
Topmost="false"
mc:Ignorable="d"
prism:ViewModelLocator.AutoWireViewModel="True"
WindowStyle="None"
WindowState="Maximized"
Title="ShellView"
d:DesignHeight="1080"
d:DesignWidth="1920">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="-1" />
</WindowChrome.WindowChrome>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Window.Resources>
<converter:InverseBooleanConverter x:Key="InverseBooleanConverter" />
<converter:TimeSpanToStringConverter x:Key="TimeSpanConverter" />
</Window.Resources>
<materialDesign:DrawerHost x:Name="MainDrawerHost"
IsLeftDrawerOpen="{Binding IsLeftDrawerOpen, Mode=TwoWay}">
<!-- ✅ 左侧抽屉内容 -->
<materialDesign:DrawerHost.LeftDrawerContent>
<StackPanel Width="220"
Background="{DynamicResource MaterialDesignPaper}">
<TextBlock Text="导航菜单"
FontSize="18"
Margin="16"
Foreground="{DynamicResource PrimaryHueMidBrush}" />
<Separator Margin="0,0,0,8" />
<Button Content="主界面"
Command="{Binding NavigateCommand}"
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
Style="{StaticResource MaterialDesignFlatButton}"
Margin="8" />
<Button Content="监控界面"
Command="{Binding NavigateCommand}"
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
Style="{StaticResource MaterialDesignFlatButton}"
Margin="8" />
<Button Content="记录界面"
Command="{Binding NavigateCommand}"
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
Style="{StaticResource MaterialDesignFlatButton}"
Margin="8" />
<Button Content="设置界面"
Command="{Binding NavigateCommand}"
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
Style="{StaticResource MaterialDesignFlatButton}"
Margin="8" />
<Button Content="更新界面"
Command="{Binding NavigateCommand}"
CommandParameter="{Binding Content, RelativeSource={RelativeSource Self}}"
Style="{StaticResource MaterialDesignFlatButton}"
Margin="8" />
</StackPanel>
</materialDesign:DrawerHost.LeftDrawerContent>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- 顶部工具栏 -->
<materialDesign:ColorZone Mode="PrimaryMid"
MouseLeftButtonDown="ColorZone_MouseLeftButtonDown">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Menu Grid.Column="0"
Background="Transparent"
Foreground="White"
VerticalAlignment="Center">
<!-- 文件菜单 -->
<MenuItem FontSize="13"
Height="50"
Header="菜单"
Foreground="White"
Command="{Binding DataContext.LeftDrawerOpenCommand, RelativeSource={RelativeSource AncestorType=Window}}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Menu"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
<!-- 工具菜单 -->
<MenuItem Header="工具"
FontSize="13"
Height="50"
Foreground="White">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Tools"
Foreground="White" />
</MenuItem.Icon>
<!-- 新建 -->
<MenuItem Header="新建"
Foreground="Black"
Command="{Binding NewCommand}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="FilePlus"
Foreground="Black" />
</MenuItem.Icon>
</MenuItem>
<!-- 打开 -->
<MenuItem Header="打开"
Foreground="Black"
Command="{Binding OpenCommand}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="FolderOpen"
Foreground="Black" />
</MenuItem.Icon>
</MenuItem>
<!-- 保存 -->
<MenuItem Header="保存"
Foreground="Black"
Command="{Binding SaveCommand}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ContentSave"
Foreground="Black" />
</MenuItem.Icon>
</MenuItem>
<!-- 另存为 -->
<MenuItem Header="另存为"
Foreground="Black"
Command="{Binding SaveAsCommand}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ContentSaveEdit"
Foreground="Black" />
</MenuItem.Icon>
</MenuItem>
<!-- 设置默认程序 -->
<MenuItem Header="设置默认程序"
Foreground="Black"
Command="{Binding SetDefaultCommand}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Cog"
Foreground="Black" />
</MenuItem.Icon>
</MenuItem>
<!-- 蜂鸣器消音 -->
<MenuItem Header="蜂鸣器消音"
FontSize="14"
Height="50"
Foreground="Black"
Command="{Binding SilenceBuzzerCommand}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="BellOff"
Foreground="Black" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="切换九宫格"
FontSize="13"
Height="50"
Foreground="White"
Command="{Binding RefreshCommand}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Refresh"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="销毁作用域"
FontSize="13"
Height="50"
Foreground="White"
Command="{Binding DestroyCommand}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Death"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
<MenuItem FontSize="14"
Height="50"
Header="运行"
IsEnabled="{Binding IsTerminate, Converter={StaticResource InverseBooleanConverter}}"
Command="{Binding RunningCommand}"
Foreground="White">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="{Binding RunIcon}"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
<MenuItem FontSize="14"
Height="50"
Header="单步执行"
IsEnabled="{Binding IsTerminate, Converter={StaticResource InverseBooleanConverter}}"
Command="{Binding RunSingleCommand}"
Foreground="White">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrowRight"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
<MenuItem FontSize="14"
Height="50"
Header="异常流程"
Command="{Binding RunAbnormalStepsCommand}"
IsEnabled="{Binding IsTerminate, Converter={StaticResource InverseBooleanConverter}}"
Foreground="White">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="AlertCircle"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
<MenuItem FontSize="14"
Height="50"
Header="复位"
Command="{Binding RestorationCommand}"
Foreground="White">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Restart"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
<MenuItem FontSize="14"
Height="50"
Foreground="White">
<MenuItem.Header>
<TextBlock>
<Run Text="运行时间:" />
<TextBlock Text="{Binding RunningTime, Converter={StaticResource TimeSpanConverter}}" />
</TextBlock>
</MenuItem.Header>
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Clock"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
</Menu>
<Menu Grid.Column="2"
Margin="0 0 20 0">
<MenuItem FontSize="13"
Height="50"
Header="最小化"
Foreground="White"
Command="{Binding MinimizeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Minimize"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
<!--<MenuItem FontSize="13"
Height="50"
Header="最大化"
Foreground="White"
Command="{Binding MaximizeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Maximize"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>-->
<MenuItem FontSize="13"
Height="50"
Header="关闭"
Foreground="White"
Command="{Binding CloseCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Close"
Foreground="White" />
</MenuItem.Icon>
</MenuItem>
</Menu>
</Grid>
<!-- 左侧菜单 -->
</materialDesign:ColorZone>
<materialDesign:DialogHost Grid.Row="1"
x:Name="DialogHost"
DialogBackground="Transparent"
Background="Transparent"
Identifier="Root">
<!-- 主内容区 -->
<Grid>
<ContentControl prism:RegionManager.RegionName="ShellViewManager" />
<Border x:Name="Overlay"
Background="#40000000"
Visibility="Collapsed"
Panel.ZIndex="1">
<StackPanel Width="150"
VerticalAlignment="Center"
Margin="0 0 0 100">
</StackPanel>
</Border>
<Border x:Name="Waitinglay"
Background="#40000000"
Visibility="Collapsed"
Panel.ZIndex="1">
<StackPanel Width="150"
VerticalAlignment="Center"
Margin="0 0 0 100">
<ProgressBar Width="80"
Height="80"
Margin="20"
IsIndeterminate="True"
Style="{StaticResource MaterialDesignCircularProgressBar}" />
<TextBlock FontSize="30"
Text="加载中......"
HorizontalAlignment="Center" />
</StackPanel>
</Border>
</Grid>
</materialDesign:DialogHost>
</Grid>
</materialDesign:DrawerHost>
</Window>

View File

@@ -0,0 +1,51 @@
using UIShare.PubEvent;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace ADP.Views
{
/// <summary>
/// ShellView.xaml 的交互逻辑
/// </summary>
public partial class ShellView : Window
{
public ShellView(IEventAggregator eventAggregator)
{
InitializeComponent();
//注册灰度遮罩层
eventAggregator.GetEvent<OverlayEvent>().Subscribe(ShowOverlay);
eventAggregator.GetEvent<WaitingEvent>().Subscribe(ShowWaitinglay);
}
private void ShowWaitinglay(bool arg)
{
Waitinglay.Visibility = arg ? Visibility.Visible : Visibility.Collapsed;
}
private void ShowOverlay(bool arg)
{
Overlay.Visibility = arg ? Visibility.Visible : Visibility.Collapsed;
}
private void ColorZone_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Window.GetWindow(this)?.DragMove();
}
}
}
}