593 lines
19 KiB
C#
593 lines
19 KiB
C#
|
|
using HandyControl.Data;
|
|||
|
|
using System.ComponentModel;
|
|||
|
|
using System.Runtime.CompilerServices;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
using System.Windows.Input;
|
|||
|
|
using System.Windows.Threading;
|
|||
|
|
using YY.Admin.Core;
|
|||
|
|
using YY.Admin.Core.Const;
|
|||
|
|
using YY.Admin.Core.EventBus;
|
|||
|
|
using YY.Admin.Core.Session;
|
|||
|
|
using YY.Admin.Services.Service.Auth;
|
|||
|
|
using YY.Admin.Views;
|
|||
|
|
|
|||
|
|
namespace YY.Admin.ViewModels
|
|||
|
|
{
|
|||
|
|
public class BaseViewModel : BindableBase, IDestructible
|
|||
|
|
{
|
|||
|
|
protected bool _isLoading;
|
|||
|
|
private string _title = string.Empty;
|
|||
|
|
|
|||
|
|
// 添加Token检查定时器
|
|||
|
|
private static DispatcherTimer? _tokenCheckTimer;
|
|||
|
|
/// <summary>
|
|||
|
|
///加载
|
|||
|
|
/// </summary>
|
|||
|
|
public bool IsLoading
|
|||
|
|
{
|
|||
|
|
get => _isLoading;
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
if (SetProperty(ref _isLoading, value))
|
|||
|
|
{
|
|||
|
|
// 触发一个虚拟方法,让派生类可以响应
|
|||
|
|
OnIsLoadingChanged();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public bool IsNotLoading => !IsLoading;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///标题
|
|||
|
|
/// </summary>
|
|||
|
|
public string Title
|
|||
|
|
{
|
|||
|
|
get => _title;
|
|||
|
|
set => SetProperty(ref _title, value);
|
|||
|
|
}
|
|||
|
|
private readonly IDialogService _dialogService;
|
|||
|
|
protected readonly IRegionManager _regionManager;
|
|||
|
|
/// <summary>
|
|||
|
|
/// 日志对象
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
protected ILoggerService _logger;
|
|||
|
|
/// <summary>
|
|||
|
|
/// 依赖注入容器
|
|||
|
|
/// </summary>
|
|||
|
|
protected IContainerExtension _container { get; }
|
|||
|
|
/// <summary>
|
|||
|
|
/// 事件汇总器,用于发布或订阅事件
|
|||
|
|
/// </summary>
|
|||
|
|
protected IEventAggregator _eventAggregator;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 当前已登录用户信息
|
|||
|
|
/// </summary>
|
|||
|
|
protected static UserContext? _userContext { get; set; }
|
|||
|
|
|
|||
|
|
private SkinType _skinType;
|
|||
|
|
|
|||
|
|
public SkinType SkinType { get => _skinType; set => SetProperty(ref _skinType, value); }
|
|||
|
|
|
|||
|
|
private SubscriptionToken? _themeChangedEventToken;
|
|||
|
|
|
|||
|
|
protected BaseViewModel(IContainerExtension container, IRegionManager regionManager)
|
|||
|
|
{
|
|||
|
|
_container = container;
|
|||
|
|
_logger = container.Resolve<ILoggerService>();
|
|||
|
|
_eventAggregator = container.Resolve<IEventAggregator>();
|
|||
|
|
this._dialogService = container.Resolve<IDialogService>();
|
|||
|
|
this._regionManager = regionManager;
|
|||
|
|
|
|||
|
|
_themeChangedEventToken = _eventAggregator.GetEvent<ThemeChangedEvent>().Subscribe(skinType => SkinType = skinType);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region 用户操作
|
|||
|
|
// 启动定时器的方法
|
|||
|
|
public static void StartTokenCheckTimer()
|
|||
|
|
{
|
|||
|
|
if (_tokenCheckTimer == null)
|
|||
|
|
{
|
|||
|
|
_tokenCheckTimer = new DispatcherTimer
|
|||
|
|
{
|
|||
|
|
Interval = TimeSpan.FromMinutes(1)
|
|||
|
|
};
|
|||
|
|
_tokenCheckTimer.Tick += CheckTokenExpiration;
|
|||
|
|
|
|||
|
|
// 捕获全局用户输入事件
|
|||
|
|
EventManager.RegisterClassHandler(typeof(Window),
|
|||
|
|
UIElement.PreviewMouseDownEvent,
|
|||
|
|
new MouseButtonEventHandler(OnUserActivity));
|
|||
|
|
EventManager.RegisterClassHandler(typeof(Window),
|
|||
|
|
UIElement.PreviewKeyDownEvent,
|
|||
|
|
new KeyEventHandler(OnUserActivity));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!_tokenCheckTimer.IsEnabled)
|
|||
|
|
{
|
|||
|
|
_tokenCheckTimer.Start();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 停止定时器的方法
|
|||
|
|
public static void StopTokenCheckTimer()
|
|||
|
|
{
|
|||
|
|
if (_tokenCheckTimer != null && _tokenCheckTimer.IsEnabled)
|
|||
|
|
{
|
|||
|
|
_tokenCheckTimer.Stop();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void OnUserActivity(object sender, EventArgs e)
|
|||
|
|
{
|
|||
|
|
var authService = ContainerLocator.Current.Resolve<ISysAuthService>();
|
|||
|
|
authService.RefreshToken(UserContext?.Token?.AccessToken);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///定时器检查方法
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sender"></param>
|
|||
|
|
/// <param name="e"></param>
|
|||
|
|
private static void CheckTokenExpiration(object? sender, EventArgs e)
|
|||
|
|
{
|
|||
|
|
// 确保在主线程执行
|
|||
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|||
|
|
{
|
|||
|
|
if (UserContext == null || UserContext.Token == null)
|
|||
|
|
{
|
|||
|
|
// 如果没有用户信息,停止定时器
|
|||
|
|
StopTokenCheckTimer();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var authService = ContainerLocator.Current.Resolve<ISysAuthService>();
|
|||
|
|
if (!authService.ValidateToken(UserContext.Token.AccessToken))
|
|||
|
|
{
|
|||
|
|
// 停止定时器防止重复触发
|
|||
|
|
StopTokenCheckTimer();
|
|||
|
|
|
|||
|
|
// 显示过期提示
|
|||
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|||
|
|
{
|
|||
|
|
var currentWindow = Application.Current.MainWindow;
|
|||
|
|
if (currentWindow != null)
|
|||
|
|
{
|
|||
|
|
var viewModel = currentWindow.DataContext as BaseViewModel;
|
|||
|
|
viewModel?.ForceLogout("您的登录已过期,请重新登录");
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 强制退出方法
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="message"></param>
|
|||
|
|
public async void ForceLogout(string message)
|
|||
|
|
{
|
|||
|
|
// 先显示对话框
|
|||
|
|
await ShowAlertAsync(message);
|
|||
|
|
|
|||
|
|
// 发布登出事件
|
|||
|
|
_eventAggregator.GetEvent<SysUserEvents.LoginOutEvent>().Publish(AppSession.CurrentUser!);
|
|||
|
|
|
|||
|
|
Logout();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 登出
|
|||
|
|
/// </summary>
|
|||
|
|
public void Logout()
|
|||
|
|
{
|
|||
|
|
// 停止定时器
|
|||
|
|
StopTokenCheckTimer();
|
|||
|
|
// 清除用户上下文
|
|||
|
|
ClearUserContext();
|
|||
|
|
// 再执行退出操作
|
|||
|
|
var authService = _container.Resolve<ISysAuthService>();
|
|||
|
|
authService.LogoutAsync();
|
|||
|
|
|
|||
|
|
// 当前窗口
|
|||
|
|
var mainWindow = Application.Current.MainWindow;
|
|||
|
|
// 跳转到登录页
|
|||
|
|
var loginWindow = _container.Resolve<LoginWindow>();
|
|||
|
|
Application.Current.MainWindow = loginWindow;
|
|||
|
|
loginWindow.Show();
|
|||
|
|
mainWindow.Close();
|
|||
|
|
|
|||
|
|
// 移除所有区域
|
|||
|
|
RemoveAllRegion();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static UserContext? UserContext
|
|||
|
|
{
|
|||
|
|
get => _userContext;
|
|||
|
|
private set
|
|||
|
|
{
|
|||
|
|
if (_userContext != value)
|
|||
|
|
{
|
|||
|
|
_userContext = value;
|
|||
|
|
// 通知静态属性变化(需要额外实现)
|
|||
|
|
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(nameof(UserContext)));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 静态属性变更通知事件
|
|||
|
|
public static event EventHandler<PropertyChangedEventArgs>? StaticPropertyChanged;
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置用户上下文
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="user"></param>
|
|||
|
|
/// <param name="token"></param>
|
|||
|
|
public static void SetUserContext(SysUser user, UserToken token)
|
|||
|
|
{
|
|||
|
|
UserContext = new UserContext
|
|||
|
|
{
|
|||
|
|
UserId = user.Id,
|
|||
|
|
TenantId = user.TenantId!.Value,
|
|||
|
|
Account = user.Account,
|
|||
|
|
AccountType = user.AccountType,
|
|||
|
|
RealName = user.RealName,
|
|||
|
|
IsSuperAdmin = user.AccountType == AccountTypeEnum.SuperAdmin,
|
|||
|
|
OrgId = user.OrgId,
|
|||
|
|
Token = token
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 清除用户上下文
|
|||
|
|
/// </summary>
|
|||
|
|
public static void ClearUserContext()
|
|||
|
|
{
|
|||
|
|
UserContext = null;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 导航
|
|||
|
|
/// <summary>
|
|||
|
|
/// 导航到指定Page
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="regionName">区域名称</param>
|
|||
|
|
/// <param name="target">目标Page名称</param>
|
|||
|
|
/// <param name="navigationCallback">导航回调函数</param>
|
|||
|
|
protected void RequestNavigate(string regionName, string target, Action<NavigationResult> navigationCallback = null)
|
|||
|
|
{
|
|||
|
|
IRegion region = _regionManager.Regions[regionName];
|
|||
|
|
if (region == null) return;
|
|||
|
|
region.RemoveAll();
|
|||
|
|
if (navigationCallback != null)
|
|||
|
|
region.RequestNavigate(target, navigationCallback);
|
|||
|
|
else
|
|||
|
|
region.RequestNavigate(target);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected void SetRegionManager(DependencyObject target)
|
|||
|
|
{
|
|||
|
|
RegionManager.SetRegionManager(target, _regionManager);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 安全导航到指定视图
|
|||
|
|
/// </summary>
|
|||
|
|
protected void SafeNavigate(string regionName, string targetView, NavigationParameters parameters = null)
|
|||
|
|
{
|
|||
|
|
ExecuteWithExceptionHandling(() =>
|
|||
|
|
{
|
|||
|
|
// 导航页面
|
|||
|
|
_regionManager.RequestNavigate(regionName, targetView, parameters);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
protected void ExecuteWithExceptionHandling(Action action)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
action();
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
HandleException(ex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void HandleException(Exception ex)
|
|||
|
|
{
|
|||
|
|
LogError("操作发生异常", ex);
|
|||
|
|
// ShowErrorDialog($"操作异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 弹出框
|
|||
|
|
/// <summary>
|
|||
|
|
/// 弹框提示
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="message">消息内容</param>
|
|||
|
|
/// <param name="callback">回调函数</param>
|
|||
|
|
protected void Alert(string message, Action<IDialogResult>? callback = null)
|
|||
|
|
{
|
|||
|
|
_dialogService.ShowDialog("AlertDialog", new DialogParameters($"message={message}"), callback);
|
|||
|
|
}
|
|||
|
|
protected Task ShowAlertAsync(string message)
|
|||
|
|
{
|
|||
|
|
var tcs = new TaskCompletionSource<bool>();
|
|||
|
|
Alert(message,result => tcs.SetResult(true));
|
|||
|
|
return tcs.Task;
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 弹出消息提示框,1秒钟自动关闭
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="message">消息内容</param>
|
|||
|
|
/// <param name="messageType">消息类型</param>
|
|||
|
|
/// <param name="callback">回调函数</param>
|
|||
|
|
protected void AlertPopup(string message, MessageTypeEnum messageType = MessageTypeEnum.Success, Action<IDialogResult> callback = null)
|
|||
|
|
{
|
|||
|
|
switch (messageType)
|
|||
|
|
{
|
|||
|
|
case MessageTypeEnum.Success:
|
|||
|
|
_dialogService.ShowDialog("SuccessDialog", new DialogParameters($"message={message}"), callback);
|
|||
|
|
break;
|
|||
|
|
case MessageTypeEnum.Error:
|
|||
|
|
_dialogService.ShowDialog("ErrorDialog", new DialogParameters($"message={message}"), callback);
|
|||
|
|
break;
|
|||
|
|
case MessageTypeEnum.Warning:
|
|||
|
|
_dialogService.ShowDialog("WarningDialog", new DialogParameters($"message={message}"), callback);
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
_dialogService.ShowDialog("SuccessDialog", new DialogParameters($"message={message}"), callback);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 确认框提示
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="message">确认框消息</param>
|
|||
|
|
/// <param name="callback">回调函数</param>
|
|||
|
|
protected void Confirm(string message, Action<IDialogResult>? callback = null)
|
|||
|
|
{
|
|||
|
|
_dialogService.ShowDialog("ConfirmDialog", new DialogParameters($"message={message}"), callback);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 异步确认框
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="message">确认消息</param>
|
|||
|
|
/// <returns>用户是否确认</returns>
|
|||
|
|
protected Task<bool> ConfirmAsync(string message)
|
|||
|
|
{
|
|||
|
|
var tcs = new TaskCompletionSource<bool>();
|
|||
|
|
|
|||
|
|
Confirm(message, result =>
|
|||
|
|
{
|
|||
|
|
// 从 IDialogResult 中提取用户选择
|
|||
|
|
var userConfirmed = result.Result == ButtonResult.Yes;
|
|||
|
|
tcs.SetResult(userConfirmed);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return tcs.Task;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 日志功能封装
|
|||
|
|
protected void LogInfo(string message, [CallerMemberName] string caller = "")
|
|||
|
|
=> _logger.Information($"[{GetType().Name}.{caller}] {message}");
|
|||
|
|
|
|||
|
|
protected void LogWarning(string message, [CallerMemberName] string caller = "")
|
|||
|
|
=> _logger.Warning($"[{GetType().Name}.{caller}] {message}");
|
|||
|
|
|
|||
|
|
protected void LogError(string message, Exception ex = null, [CallerMemberName] string caller = "")
|
|||
|
|
=> _logger.Error($"[{GetType().Name}.{caller}] {message}", ex);
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 异常处理封装
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="asyncAction"></param>
|
|||
|
|
/// <param name="onFinally"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
protected async Task ExecuteAsync(Func<Task> asyncAction, Action? onFinally = null)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
IsLoading = true;
|
|||
|
|
await asyncAction();
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
HandleException(ex);
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
IsLoading = false;
|
|||
|
|
onFinally?.Invoke();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 窗口管理
|
|||
|
|
/// </summary>
|
|||
|
|
/// <typeparam name="T"></typeparam>
|
|||
|
|
protected void SwitchMainWindow<T>() where T : Window
|
|||
|
|
{
|
|||
|
|
ExecuteWithExceptionHandling(() =>
|
|||
|
|
{
|
|||
|
|
var currentWindow = Application.Current.MainWindow;
|
|||
|
|
var newWindow = _container.Resolve<T>();
|
|||
|
|
|
|||
|
|
Application.Current.MainWindow?.Hide();
|
|||
|
|
Application.Current.MainWindow = newWindow;
|
|||
|
|
newWindow.Show();
|
|||
|
|
|
|||
|
|
currentWindow?.Close();
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 资源管理
|
|||
|
|
/// </summary>
|
|||
|
|
/// <typeparam name="T"></typeparam>
|
|||
|
|
/// <param name="resourceKey"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
/// <exception cref="ResourceNotFoundException"></exception>
|
|||
|
|
protected T GetResource<T>(string resourceKey)
|
|||
|
|
{
|
|||
|
|
if (Application.Current.TryFindResource(resourceKey) is T resource)
|
|||
|
|
{
|
|||
|
|
return resource;
|
|||
|
|
}
|
|||
|
|
throw new ResourceNotFoundException($"资源未找到: {resourceKey}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 移除区域,包括清空区域内的内容,导航日志
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="regionName">区域名称</param>
|
|||
|
|
protected void RemoveRegion(string regionName)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(regionName))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (!_regionManager.Regions.ContainsRegionWithName(regionName))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var region = _regionManager.Regions[regionName];
|
|||
|
|
RemoveRegion(region);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 移除区域,包括清空区域内的内容,导航日志
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="region"></param>
|
|||
|
|
protected void RemoveRegion(IRegion region)
|
|||
|
|
{
|
|||
|
|
if (region == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
// 清空区域内容
|
|||
|
|
region.RemoveAll();
|
|||
|
|
|
|||
|
|
// 清空导航历史
|
|||
|
|
region.NavigationService?.Journal?.Clear();
|
|||
|
|
|
|||
|
|
// 从区域管理器中移除区域
|
|||
|
|
_regionManager.Regions.Remove(region.Name);
|
|||
|
|
|
|||
|
|
_logger.Debug($"移除区域{region.Name}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 移除所有区域
|
|||
|
|
/// </summary>
|
|||
|
|
protected void RemoveAllRegion()
|
|||
|
|
{
|
|||
|
|
foreach (var region in _regionManager.Regions.ToList())
|
|||
|
|
{
|
|||
|
|
RemoveRegion(region);
|
|||
|
|
}
|
|||
|
|
_logger.Debug($"移除所有区域");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 移除区域视图
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="regionName">区域名称</param>
|
|||
|
|
/// <param name="viewName">视图名称</param>
|
|||
|
|
protected void RemoveView(string regionName, string? viewName)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(regionName) || string.IsNullOrEmpty(viewName))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (!_regionManager.Regions.ContainsRegionWithName(regionName))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var region = _regionManager.Regions[regionName];
|
|||
|
|
// 查找并移除指定的视图
|
|||
|
|
var viewToRemove = region.Views.FirstOrDefault(v =>
|
|||
|
|
{
|
|||
|
|
// 根据视图名称或类型来匹配
|
|||
|
|
var viewType = v.GetType();
|
|||
|
|
return viewType.Name == viewName || viewType.Name == viewName + "View";
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (viewToRemove != null)
|
|||
|
|
{
|
|||
|
|
region.Remove(viewToRemove);
|
|||
|
|
_logger.Debug($"从区域{regionName}移除视图{viewName}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 移除区域ContentRegion视图
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="viewName"></param>
|
|||
|
|
protected void RemoveContentRegionView(string? viewName)
|
|||
|
|
{
|
|||
|
|
RemoveView(CommonConst.ContentRegion, viewName);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 移除区域所有视图
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="regionName">区域名称</param>
|
|||
|
|
protected void RemoveAllView(string regionName)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(regionName))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (!_regionManager.Regions.ContainsRegionWithName(regionName))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
var region = _regionManager.Regions[regionName];
|
|||
|
|
region.RemoveAll();
|
|||
|
|
_logger.Debug($"移除区域{regionName}所有视图");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 当 IsLoading 变化时的回调方法
|
|||
|
|
/// </summary>
|
|||
|
|
protected virtual void OnIsLoadingChanged()
|
|||
|
|
{
|
|||
|
|
RaisePropertyChanged(nameof(IsNotLoading));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 清理资源
|
|||
|
|
/// </summary>
|
|||
|
|
protected virtual void CleanUp()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 清空资源
|
|||
|
|
/// 执行时机:从Region移除View 或 导航到另一个View时
|
|||
|
|
/// </summary>
|
|||
|
|
public void Destroy()
|
|||
|
|
{
|
|||
|
|
if (_themeChangedEventToken != null)
|
|||
|
|
{
|
|||
|
|
_eventAggregator.GetEvent<ThemeChangedEvent>().Unsubscribe(_themeChangedEventToken);
|
|||
|
|
_themeChangedEventToken = null;
|
|||
|
|
}
|
|||
|
|
// 清理派生类的资源
|
|||
|
|
CleanUp();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 自定义异常类型
|
|||
|
|
public class ResourceNotFoundException : Exception
|
|||
|
|
{
|
|||
|
|
public ResourceNotFoundException(string message) : base(message) { }
|
|||
|
|
}
|
|||
|
|
}
|