using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml.Controls;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Services;
namespace XFEEDToolBox.ViewModels;
public partial class ToolboxViewModel
{
[ObservableProperty] public partial string MarketCacheUsageText { get; set; }="正在读取缓存占用…";
[ObservableProperty] public partial string MarketCacheLegacyNotice { get; set; }="已有缓存保留到你点击清理。";
[ObservableProperty,NotifyPropertyChangedFor(nameof(HasMarketCacheStatus))]
public partial string MarketCacheStatus { get; set; }="";
[ObservableProperty] public partial InfoBarSeverity MarketCacheStatusSeverity { get; set; }=InfoBarSeverity.Informational;
[ObservableProperty] public partial bool MarketCacheBusy { get; set; }
public bool HasMarketCacheStatus=>MarketCacheStatus.Length>0;
public bool MarketCacheClearAvailable=>!MarketCacheBusy&&MarketCacheBlockReason.Length==0;
public bool MarketCacheRefreshAvailable=>!MarketCacheBusy;
public string MarketCacheBlockReason
{
get
{
if(RunActive||NavigationActive||SystemFlightActive||NavigationRouteBusy)return "请先停止自动跑商或导航,再清理行情缓存。";
if(SessionBusy)return "请等待会话操作完成,再清理行情缓存。";
if(TradeRegionBusy)return "请等待行情范围保存完成,再清理缓存。";
if(ImportSystemCommand.IsRunning||ImportSpanshCommand.IsRunning||ImportCaptureCommand.IsRunning)
return "请先完成或取消数据导入,再清理行情缓存。";
if(IsBusy&&!MarketCacheBusy)return "数据操作进行中,请稍后清理行情缓存。";
return "";
}
}
private void InitializeMarketCacheSettings()
{
runtime.ClearMarketCacheBlockReason=()=>MarketCacheBlockReason is {Length:>0} reason?reason:null;
PropertyChanged+=OnMarketCacheSettingsStateChanged;
foreach(var command in new IAsyncRelayCommand[]{ImportSystemCommand,ImportSpanshCommand,ImportCaptureCommand})
command.PropertyChanged+=OnMarketCacheImportStateChanged;
}
private void OnMarketCacheSettingsStateChanged(object? sender,PropertyChangedEventArgs args)
{
if(args.PropertyName is nameof(RunActive) or nameof(NavigationActive) or nameof(SystemFlightActive)
or nameof(NavigationRouteBusy) or nameof(SessionBusy) or nameof(IsBusy) or nameof(MarketCacheBusy))
RefreshMarketCacheSettingsAvailability();
}
private void OnMarketCacheImportStateChanged(object? sender,PropertyChangedEventArgs args)
{if(args.PropertyName==nameof(IAsyncRelayCommand.IsRunning))RefreshMarketCacheSettingsAvailability();}
private void RefreshMarketCacheSettingsAvailability()
{
if(!dispatcher.HasThreadAccess){dispatcher.TryEnqueue(RefreshMarketCacheSettingsAvailability);return;}
OnPropertyChanged(nameof(MarketCacheClearAvailable));OnPropertyChanged(nameof(MarketCacheRefreshAvailable));OnPropertyChanged(nameof(MarketCacheBlockReason));
ClearMarketCacheCommand.NotifyCanExecuteChanged();RefreshMarketCacheUsageCommand.NotifyCanExecuteChanged();
}
private static string MarketCacheSize(long bytes)
{
var amount=(double)Math.Max(0,bytes);var units=new[]{"B","KiB","MiB","GiB","TiB"};var unit=0;
while(amount>=1024&&unit<units.Length-1){amount/=1024;unit++;}
return unit==0?$"{amount:N0} B":$"{amount:N2} {units[unit]}";
}
private void ApplyMarketCacheUsage(MarketCacheUsage usage)
{
MarketCacheUsageText=$"已占用 {MarketCacheSize(usage.Bytes)} · {usage.Files:N0} 个文件";
MarketCacheLegacyNotice=usage.HasLegacyFullCache?"包含旧的全量行情,点击清理后才会移除。":"已有行情缓存会保留到你点击清理。";
}
[RelayCommand(CanExecute=nameof(MarketCacheRefreshAvailable))]
private async Task RefreshMarketCacheUsageAsync()
{
if(MarketCacheBusy)return;
MarketCacheBusy=true;
try{ApplyMarketCacheUsage(await runtime.GetMarketCacheUsageAsync(lifetime.Token));}
catch(OperationCanceledException)when(lifetime.IsCancellationRequested){}
catch(Exception error)
{
MarketCacheUsageText="缓存占用暂时无法读取";MarketCacheStatus="读取缓存占用失败,请查看日志详情。";MarketCacheStatusSeverity=InfoBarSeverity.Warning;
runtime.ReportDiagnostic("market.cache.settings.usage","行情缓存",error,ActivitySeverity.Warning,"读取缓存占用失败,请查看日志详情。");
}
finally{MarketCacheBusy=false;}
}
[RelayCommand(CanExecute=nameof(MarketCacheClearAvailable))]
private async Task ClearMarketCacheAsync()
{
if(!MarketCacheClearAvailable)return;
MarketCacheBusy=true;IsBusy=true;MarketCacheStatus="正在清理行情缓存…";MarketCacheStatusSeverity=InfoBarSeverity.Informational;
CancelMarketRead();Interlocked.Increment(ref marketRequest);
try
{
var result=await runtime.ClearMarketCacheAsync(lifetime.Token);ApplyMarketCacheUsage(result.Usage);
if(result.Succeeded)
{
var retained=result.Usage.HasLegacyFullCache||result.Message.Contains("隔离文件",StringComparison.Ordinal);
MarketCacheStatus=retained?$"已释放 {MarketCacheSize(result.FreedBytes)};部分缓存仍被占用,可稍后重试。":$"已释放 {MarketCacheSize(result.FreedBytes)},后续按周边范围重新累积行情。";
MarketCacheStatusSeverity=retained?InfoBarSeverity.Warning:InfoBarSeverity.Success;
runtime.Log("行情缓存",MarketCacheStatus+" "+result.Message);OnDataChanged(RuntimeChange.Markets);
}
else
{
var detail=result.Message??"行情缓存清理被拒绝。";
MarketCacheStatus=detail.Length is >0 and <=90&&!detail.Contains(":\\",StringComparison.Ordinal)&&!detail.Contains('\n')
?detail:"缓存未清理,请停止占用行情数据的操作后重试。";
MarketCacheStatusSeverity=InfoBarSeverity.Warning;
runtime.ReportDiagnostic("market.cache.settings.clear","行情缓存",new IOException(detail),ActivitySeverity.Warning,MarketCacheStatus);
}
}
catch(OperationCanceledException)when(lifetime.IsCancellationRequested){}
catch(Exception error)
{
MarketCacheStatus="缓存清理未完成,请查看日志详情。";MarketCacheStatusSeverity=InfoBarSeverity.Error;
runtime.ReportDiagnostic("market.cache.settings.clear","行情缓存",error,ActivitySeverity.Error,"缓存清理未完成,请查看日志详情。");
}
finally{IsBusy=false;MarketCacheBusy=false;}
}
}
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml.Controls;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Services;
namespace XFEEDToolBox.ViewModels;
public partial class ToolboxViewModel
{
[ObservableProperty] public partial string MarketCacheUsageText { get; set; }="正在读取缓存占用…";
[ObservableProperty] public partial string MarketCacheLegacyNotice { get; set; }="已有缓存保留到你点击清理。";
[ObservableProperty,NotifyPropertyChangedFor(nameof(HasMarketCacheStatus))]
public partial string MarketCacheStatus { get; set; }="";
[ObservableProperty] public partial InfoBarSeverity MarketCacheStatusSeverity { get; set; }=InfoBarSeverity.Informational;
[ObservableProperty] public partial bool MarketCacheBusy { get; set; }
public bool HasMarketCacheStatus=>MarketCacheStatus.Length>0;
public bool MarketCacheClearAvailable=>!MarketCacheBusy&&MarketCacheBlockReason.Length==0;
public bool MarketCacheRefreshAvailable=>!MarketCacheBusy;
public string MarketCacheBlockReason
{
get
{
if(RunActive||NavigationActive||SystemFlightActive||NavigationRouteBusy)return "请先停止自动跑商或导航,再清理行情缓存。";
if(SessionBusy)return "请等待会话操作完成,再清理行情缓存。";
if(TradeRegionBusy)return "请等待行情范围保存完成,再清理缓存。";
if(ImportSystemCommand.IsRunning||ImportSpanshCommand.IsRunning||ImportCaptureCommand.IsRunning)
return "请先完成或取消数据导入,再清理行情缓存。";
if(IsBusy&&!MarketCacheBusy)return "数据操作进行中,请稍后清理行情缓存。";
return "";
}
}
private void InitializeMarketCacheSettings()
{
runtime.ClearMarketCacheBlockReason=()=>MarketCacheBlockReason is {Length:>0} reason?reason:null;
PropertyChanged+=OnMarketCacheSettingsStateChanged;
foreach(var command in new IAsyncRelayCommand[]{ImportSystemCommand,ImportSpanshCommand,ImportCaptureCommand})
command.PropertyChanged+=OnMarketCacheImportStateChanged;
}
private void OnMarketCacheSettingsStateChanged(object? sender,PropertyChangedEventArgs args)
{
if(args.PropertyName is nameof(RunActive) or nameof(NavigationActive) or nameof(SystemFlightActive)
or nameof(NavigationRouteBusy) or nameof(SessionBusy) or nameof(IsBusy) or nameof(MarketCacheBusy))
RefreshMarketCacheSettingsAvailability();
}
private void OnMarketCacheImportStateChanged(object? sender,PropertyChangedEventArgs args)
{if(args.PropertyName==nameof(IAsyncRelayCommand.IsRunning))RefreshMarketCacheSettingsAvailability();}
private void RefreshMarketCacheSettingsAvailability()
{
if(!dispatcher.HasThreadAccess){dispatcher.TryEnqueue(RefreshMarketCacheSettingsAvailability);return;}
OnPropertyChanged(nameof(MarketCacheClearAvailable));OnPropertyChanged(nameof(MarketCacheRefreshAvailable));OnPropertyChanged(nameof(MarketCacheBlockReason));
ClearMarketCacheCommand.NotifyCanExecuteChanged();RefreshMarketCacheUsageCommand.NotifyCanExecuteChanged();
}
private static string MarketCacheSize(long bytes)
{
var amount=(double)Math.Max(0,bytes);var units=new[]{"B","KiB","MiB","GiB","TiB"};var unit=0;
while(amount>=1024&&unit<units.Length-1){amount/=1024;unit++;}
return unit==0?$"{amount:N0} B":$"{amount:N2} {units[unit]}";
}
private void ApplyMarketCacheUsage(MarketCacheUsage usage)
{
MarketCacheUsageText=$"已占用 {MarketCacheSize(usage.Bytes)} · {usage.Files:N0} 个文件";
MarketCacheLegacyNotice=usage.HasLegacyFullCache?"包含旧的全量行情,点击清理后才会移除。":"已有行情缓存会保留到你点击清理。";
}
[RelayCommand(CanExecute=nameof(MarketCacheRefreshAvailable))]
private async Task RefreshMarketCacheUsageAsync()
{
if(MarketCacheBusy)return;
MarketCacheBusy=true;
try{ApplyMarketCacheUsage(await runtime.GetMarketCacheUsageAsync(lifetime.Token));}
catch(OperationCanceledException)when(lifetime.IsCancellationRequested){}
catch(Exception error)
{
MarketCacheUsageText="缓存占用暂时无法读取";MarketCacheStatus="读取缓存占用失败,请查看日志详情。";MarketCacheStatusSeverity=InfoBarSeverity.Warning;
runtime.ReportDiagnostic("market.cache.settings.usage","行情缓存",error,ActivitySeverity.Warning,"读取缓存占用失败,请查看日志详情。");
}
finally{MarketCacheBusy=false;}
}
[RelayCommand(CanExecute=nameof(MarketCacheClearAvailable))]
private async Task ClearMarketCacheAsync()
{
if(!MarketCacheClearAvailable)return;
MarketCacheBusy=true;IsBusy=true;MarketCacheStatus="正在清理行情缓存…";MarketCacheStatusSeverity=InfoBarSeverity.Informational;
CancelMarketRead();Interlocked.Increment(ref marketRequest);
try
{
var result=await runtime.ClearMarketCacheAsync(lifetime.Token);ApplyMarketCacheUsage(result.Usage);
if(result.Succeeded)
{
var retained=result.Usage.HasLegacyFullCache||result.Message.Contains("隔离文件",StringComparison.Ordinal);
MarketCacheStatus=retained?$"已释放 {MarketCacheSize(result.FreedBytes)};部分缓存仍被占用,可稍后重试。":$"已释放 {MarketCacheSize(result.FreedBytes)},后续按周边范围重新累积行情。";
MarketCacheStatusSeverity=retained?InfoBarSeverity.Warning:InfoBarSeverity.Success;
runtime.Log("行情缓存",MarketCacheStatus+" "+result.Message);OnDataChanged(RuntimeChange.Markets);
}
else
{
var detail=result.Message??"行情缓存清理被拒绝。";
MarketCacheStatus=detail.Length is >0 and <=90&&!detail.Contains(":\\",StringComparison.Ordinal)&&!detail.Contains('\n')
?detail:"缓存未清理,请停止占用行情数据的操作后重试。";
MarketCacheStatusSeverity=InfoBarSeverity.Warning;
runtime.ReportDiagnostic("market.cache.settings.clear","行情缓存",new IOException(detail),ActivitySeverity.Warning,MarketCacheStatus);
}
}
catch(OperationCanceledException)when(lifetime.IsCancellationRequested){}
catch(Exception error)
{
MarketCacheStatus="缓存清理未完成,请查看日志详情。";MarketCacheStatusSeverity=InfoBarSeverity.Error;
runtime.ReportDiagnostic("market.cache.settings.clear","行情缓存",error,ActivitySeverity.Error,"缓存清理未完成,请查看日志详情。");
}
finally{IsBusy=false;MarketCacheBusy=false;}
}
}