using HttpFileServer.Core;using HttpFileServer.Infrastructure;using HttpFileServer.Models;using HttpFileServer.Servers;using HttpFileServer.Services;using HttpFileServer.Utils;using HttpFileServer.Views;using QRCoder;using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.IO;using System.Linq;using System.Net.NetworkInformation;using System.Runtime.CompilerServices;using System.Windows;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Threading;namespace HttpFileServer.ViewModels{public class ShellViewModel : ViewModelBase{#region Fieldsprivate ConfigService _cfgSrv;private Config _config;private bool _enableUpload = false;private bool _enableAuth = true;private bool _strictAuthMode = false;private bool _enableHttps = false;private ushort _httpsPort = 443;private ImageSource _ipv4QrImage;private string _ipv4Text;private ImageSource _ipv6QrImage;private string _ipv6Text;private bool _isRunning = false;private ushort _listenPort = 80;private string _logContent = string.Empty;private bool _logIsReadOnly = false;private ObservableCollection<NetworkAdapterModel> _networkAdapters = new ObservableCollection<NetworkAdapterModel>();private NetworkAdapterModel _selectedNetworkAdapter;private int _selectedTabIndex = 0;private bool _shareTabEnabled = false;private string _sourceDir;private ServerStatus _status = ServerStatus.Ready;private string _themeMode = "Light";private bool _useWebServer = false;private string _siteName = "HttpFileServer";// Light / Dark / Systemprivate ObservableCollection<VirtualDirectoryInfo> _virtualDirectoryItems = new ObservableCollection<VirtualDirectoryInfo>();private VirtualDirectoryInfo _selectedVirtualDirectoryItem;private ObservableCollection<UserAccount> _userItems = new ObservableCollection<UserAccount>();private UserAccount _selectedUserItem;#endregion Fields#region Constructorspublic ShellViewModel(){Title = "File Server";// capture app instance if availablevar _app = Application.Current as App;RequestModels = new ObservableCollection<RequestModel>();CommandStartServer = new CommandImpl(OnRequestStartServer, CanStartServer);CommandStopServer = new CommandImpl(OnRequestStopServer, CanStopServer);CommandToggleTheme = new CommandImpl(OnToggleTheme);CommandAddVirtualDir = new CommandImpl(OnAddVirtualDir);CommandRemoveVirtualDir = new CommandImpl(OnRemoveVirtualDir);CommandApplyVirtualDirs = new CommandImpl(OnApplyVirtualDirs);CommandAddUser = new CommandImpl(OnAddUser);CommandRemoveUser = new CommandImpl(OnRemoveUser);CommandApplyUsers = new CommandImpl(OnApplyUsers);// 默认:选中 配置 tab,分享禁用,日志在停止时可编辑SelectedTabIndex = 0;ShareTabEnabled = false;LogIsReadOnly = IsRunning; // false by default_cfgSrv = new ConfigService();// 初始根据系统主题ThemeMode = DetectSystemTheme();ApplyThemeResources();}#endregion Constructors#region Propertiesprivate bool _autoStartOnLaunch = false;private bool _autoStartWithSystem = false;private bool _MinimizeToTrayAfterAutoStart = true;public bool AutoStartOnLaunch{get => _autoStartOnLaunch;set => SetProperty(ref _autoStartOnLaunch, value);}public bool AutoStartWithSystem{get => _autoStartWithSystem;set{if (SetProperty(ref _autoStartWithSystem, value)){AutoStartHelper.SetAutoStart(value);}}}public CommandImpl CommandStartServer { get; private set; }public CommandImpl CommandStopServer { get; private set; }public CommandImpl CommandToggleTheme { get; private set; }public CommandImpl CommandAddVirtualDir { get; private set; }public CommandImpl CommandRemoveVirtualDir { get; private set; }public CommandImpl CommandApplyVirtualDirs { get; private set; }public CommandImpl CommandAddUser { get; private set; }public CommandImpl CommandRemoveUser { get; private set; }public CommandImpl CommandApplyUsers { get; private set; }/// <summary>/// 虚拟目录列表(绑定到 DataGrid)/// </summary>public ObservableCollection<VirtualDirectoryInfo> VirtualDirectoryItems{get => _virtualDirectoryItems;set => SetProperty(ref _virtualDirectoryItems, value);}/// <summary>/// 选中的虚拟目录项/// </summary>public VirtualDirectoryInfo SelectedVirtualDirectoryItem{get => _selectedVirtualDirectoryItem;set => SetProperty(ref _selectedVirtualDirectoryItem, value);}public ObservableCollection<UserAccount> UserItems{get => _userItems;set => SetProperty(ref _userItems, value);}public UserAccount SelectedUserItem{get => _selectedUserItem;set => SetProperty(ref _selectedUserItem, value);}public Dispatcher Dispatcher { get; set; }public bool EnableUpload{get => _enableUpload;set => SetProperty(ref _enableUpload, value);}/// <summary>/// 是否启用用户认证与权限控制/// </summary>public bool EnableAuth{get => _enableAuth;set{if (SetProperty(ref _enableAuth, value) && !value)StrictAuthMode = false; // 禁用认证时自动关闭严格模式}}/// <summary>/// 严格认证模式:未登录用户访问任何 URL 均跳转到独立登录页/// </summary>public bool StrictAuthMode{get => _strictAuthMode;set => SetProperty(ref _strictAuthMode, value);}/// <summary>/// 是否启用 HTTPS/// </summary>public bool EnableHttps{get => _enableHttps;set{if (IsRunning)return;SetProperty(ref _enableHttps, value);}}/// <summary>/// HTTPS 端口/// </summary>public ushort HttpsPort{get => _httpsPort;set{if (IsRunning)return;if (SetProperty(ref _httpsPort, value)){UpdateShareInfo();}}}public IFileServer FileServer { get; private set; }public ImageSource IPv4QrImage { get => _ipv4QrImage; private set => SetProperty(ref _ipv4QrImage, value); }public string IPv4Text { get => _ipv4Text; private set => SetProperty(ref _ipv4Text, value); }public ImageSource IPv6QrImage { get => _ipv6QrImage; private set => SetProperty(ref _ipv6QrImage, value); }public string IPv6Text { get => _ipv6Text; private set => SetProperty(ref _ipv6Text, value); }public bool IsRunning{get => _isRunning;set => SetProperty(ref _isRunning, value);}public ushort ListenPort{get => _listenPort;set{// Prevent changing the listen port while server is runningif (IsRunning)return;if (SetProperty(ref _listenPort, value)){// Update share info in UI to reflect new port immediatelyUpdateShareInfo();}}}public string LogContent{get => _logContent;private set => SetProperty(ref _logContent, value);}public bool LogIsReadOnly{get => _logIsReadOnly;set => SetProperty(ref _logIsReadOnly, value);}public bool MinimizeToTrayAfterAutoStart{get => _MinimizeToTrayAfterAutoStart;set => SetProperty(ref _MinimizeToTrayAfterAutoStart, value);}public ObservableCollection<NetworkAdapterModel> NetworkAdapters { get => _networkAdapters; }public ObservableCollection<RequestModel> RequestModels { get; private set; }public NetworkAdapterModel SelectedNetworkAdapter{get => _selectedNetworkAdapter;set{if (SetProperty(ref _selectedNetworkAdapter, value)){UpdateShareInfo();}}}public int SelectedTabIndex{get => _selectedTabIndex;set => SetProperty(ref _selectedTabIndex, value);}public bool ShareTabEnabled{get => _shareTabEnabled;set => SetProperty(ref _shareTabEnabled, value);}public string SourceDir{get => _sourceDir;set => SetProperty(ref _sourceDir, value);}public ServerStatus Status{get => _status;set => SetProperty(ref _status, value);}public string ThemeMode { get => _themeMode; set => SetProperty(ref _themeMode, value); }public bool UseWebServer{get => _useWebServer;set => SetProperty(ref _useWebServer, value);}/// <summary>/// 站点名称/// </summary>public string SiteName{get => _siteName;set{if (SetProperty(ref _siteName, value)){// 服务运行时即时推送到服务器并清缓存if (IsRunning && FileServer is HttpFileServerBase hfs){hfs.UpdateSiteName(value);}}}}#endregion Properties#region Methodsprotected override void OnPropertyChanged([CallerMemberName] string propertyName = null){base.OnPropertyChanged(propertyName);if (propertyName.Equals("SourceDir")){CommandStartServer?.RaiseCanExecuteChanged();}}protected override void OnViewLoaded(object sender){base.OnViewLoaded(sender);var cfg = _cfgSrv.GetConfig<Config>();if (cfg == null)cfg = new Config();cfg.RemoveDuplicates(); //清除重复数据_config = cfg;SourceDir = cfg.RootDir;ListenPort = cfg.Port;EnableUpload = cfg.EnableUpload;EnableAuth = cfg.EnableAuth;StrictAuthMode = cfg.StrictAuthMode;EnableHttps = cfg.EnableHttps;HttpsPort = cfg.HttpsPort;UseWebServer = cfg.UseWebServer;SiteName = cfg.SiteName ?? "HttpFileServer";// 加载虚拟目录配置(ViewModel 层去重)VirtualDirectoryItems.Clear();if (cfg.VirtualDirectories != null){var distinctVdirs = cfg.VirtualDirectories.GroupBy(v => $"{v.Name ?? ""}|{v.PhysicalPath?.TrimEnd('\\', '/') ?? ""}", StringComparer.OrdinalIgnoreCase).Select(g => g.First());foreach (var vdir in distinctVdirs){VirtualDirectoryItems.Add(new VirtualDirectoryInfo{Name = vdir.Name,PhysicalPath = vdir.PhysicalPath,Description = vdir.Description,AllowUpload = vdir.AllowUpload});}}// 加载用户配置(ViewModel 层去重,不修改 _config 原始数据)UserItems.Clear();if (cfg.Users != null){var distinctUsers = cfg.Users.GroupBy(u => u.Username, StringComparer.OrdinalIgnoreCase).Select(g => g.First());foreach (var u in distinctUsers){UserItems.Add(new UserAccount{Username = u.Username,Password = u.Password,AllowedVirtualDirs = u.AllowedVirtualDirs?.ToList(),CanUpload = u.CanUpload});}}AutoStartOnLaunch = cfg.AutoStartOnLaunch;AutoStartWithSystem = cfg.AutoStartWithSystem;MinimizeToTrayAfterAutoStart = cfg.MinimizeToTrayAfterAutoStart;// 加载保存的主题模式if (!string.IsNullOrWhiteSpace(cfg.ThemeMode)) ThemeMode = cfg.ThemeMode; else ThemeMode = DetectSystemTheme();ApplyThemeResources();if (AutoStartHelper.IsProcessRunWithAutoStart() && _config.MinimizeToTrayAfterAutoStart){var shell = sender as ShellView;shell.WindowState = WindowState.Minimized;}// If application started with --debug-resource, show debug info in titlestring debugRes = null;try{var app = System.Windows.Application.Current as App;if (app != null)debugRes = app.DebugResourcePath;}catch { }if (!string.IsNullOrWhiteSpace(debugRes)){Title = $"File Server - [ Html Debug ] -- {debugRes}";LogContent += ($"[ Html Debug ]{Environment.NewLine}{debugRes}{Environment.NewLine}{Environment.NewLine}");}if ((AutoStartHelper.IsProcessRunWithAutoStart() && _config.AutoStartWithSystem) || _config.AutoStartOnLaunch){OnRequestStartServer();}Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;// Populate network adapters for Share tabLoadNetworkAdapters();}protected override void OnViewUnLoaded(object sender){if (IsRunning)OnRequestStopServer();_config.RootDir = SourceDir;_config.Port = (ushort)ListenPort;_config.EnableUpload = EnableUpload;_config.EnableAuth = EnableAuth;_config.StrictAuthMode = StrictAuthMode;_config.EnableHttps = EnableHttps;_config.HttpsPort = HttpsPort;_config.UseWebServer = UseWebServer;_config.ThemeMode = ThemeMode; // 保存当前主题模式_config.SiteName = SiteName;// 保存虚拟目录配置_config.VirtualDirectories = VirtualDirectoryItems.ToList();// 保存用户配置_config.Users = UserItems.ToList();_config.AutoStartOnLaunch = AutoStartOnLaunch;_config.AutoStartWithSystem = AutoStartWithSystem;_config.MinimizeToTrayAfterAutoStart = MinimizeToTrayAfterAutoStart;_cfgSrv.SaveConfig(_config);base.OnViewUnLoaded(sender);}private void ApplyThemeResources(){var dict = GetWindowResources();string mode = ThemeMode == "System" ? DetectSystemTheme() : ThemeMode;if (mode == "Dark"){dict["WindowBackgroundBrush"] = new SolidColorBrush(Color.FromRgb(0x1E, 0x1E, 0x1E));dict["WindowForegroundBrush"] = new SolidColorBrush(Colors.WhiteSmoke);dict["PanelBackgroundBrush"] = new SolidColorBrush(Color.FromRgb(0x2A, 0x2A, 0x2A));dict["PanelBorderBrush"] = new SolidColorBrush(Color.FromRgb(0x44, 0x44, 0x44));dict["AccentBrush"] = new SolidColorBrush(Color.FromRgb(0x3B, 0x82, 0xF6));// softer off-white for QR background in dark mode to reduce glaredict["QrBackgroundBrush"] = new SolidColorBrush(Color.FromRgb(0xEE, 0xEE, 0xEE));}else // Light{dict["WindowBackgroundBrush"] = new SolidColorBrush(Colors.White);dict["WindowForegroundBrush"] = new SolidColorBrush(Color.FromRgb(0x11, 0x11, 0x11));dict["PanelBackgroundBrush"] = new SolidColorBrush(Color.FromRgb(0xF5, 0xF5, 0xF5));dict["PanelBorderBrush"] = new SolidColorBrush(Color.FromRgb(0xDD, 0xDD, 0xDD));dict["AccentBrush"] = new SolidColorBrush(Color.FromRgb(0x3B, 0x82, 0xF6));// standard white QR background in light modedict["QrBackgroundBrush"] = new SolidColorBrush(Colors.White);}}private bool CanStartServer(){return !IsRunning && !string.IsNullOrWhiteSpace(SourceDir);}private bool CanStopServer(){return IsRunning;}private string DetectSystemTheme(){// 简单使用系统窗口颜色亮度判断var col = SystemParameters.WindowGlassColor; // Win7+ Aero色var brightness = (col.R * 299 + col.G * 587 + col.B * 114) / 1000;return brightness < 128 ? "Dark" : "Light";}private void Dispatcher_ShutdownStarted(object sender, EventArgs e){OnViewUnLoaded(sender);}private void FileServer_LogGenerated(object sender, string e){LogContent += $"{e}{Environment.NewLine}";}private void FileServer_NewReqeustIn(object sender, RequestModel e){Dispatcher?.InvokeAsync(() =>{RequestModels.Add(e);});}private void FileServer_RequestOut(object sender, RequestModel e){Dispatcher?.InvokeAsync(() =>{RequestModels.Remove(e);});}private ImageSource GenerateQrImage(string text){try{using (var gen = new QRCodeGenerator()){var data = gen.CreateQrCode(text, QRCodeGenerator.ECCLevel.Q);var pngQr = new PngByteQRCode(data);var pngBytes = pngQr.GetGraphic(10);using (var ms = new MemoryStream(pngBytes)){var img = new BitmapImage();img.BeginInit();img.CacheOption = BitmapCacheOption.OnLoad;img.StreamSource = ms;img.EndInit();img.Freeze();return img;}}}catch{return null;}}private ResourceDictionary GetWindowResources(){foreach (Window w in Application.Current.Windows){if (w.DataContext == this)return w.Resources; // 当前窗口资源}return Application.Current.Resources; //退回应用级}private bool IsPortInUse(int port){try{var ipProps = IPGlobalProperties.GetIPGlobalProperties();var listeners = ipProps.GetActiveTcpListeners();foreach (var ep in listeners){if (ep.Port == port)return true;}}catch{// If check fails, conservatively assume port is not in use}return false;}private void LoadNetworkAdapters(){try{NetworkAdapters.Clear();var nics = NetworkInterface.GetAllNetworkInterfaces().Where(n => n.OperationalStatus == OperationalStatus.Up && n.NetworkInterfaceType != NetworkInterfaceType.Loopback);foreach (var nic in nics){var props = nic.GetIPProperties();var addrs = props.UnicastAddresses.Where(u => u.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork || u.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6).Select(u => u.Address).ToArray();var model = new NetworkAdapterModel{Id = nic.Id,Name = string.IsNullOrWhiteSpace(nic.Description) ? nic.Name : nic.Description,IPv4 = addrs.FirstOrDefault(a => a.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)?.ToString(),IPv6 = addrs.FirstOrDefault(a => a.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)?.ToString()};NetworkAdapters.Add(model);}SelectedNetworkAdapter = NetworkAdapters.FirstOrDefault();}catch { }}private void OnRequestStartServer(){if (IsRunning)return;// Check if desired HTTP port is already in use by another processif (IsPortInUse(ListenPort)){LogContent += $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} HTTP 端口 {ListenPort} 已被占用,启动被拒绝。{Environment.NewLine}";// Switch to logs tab so the user can see the failure messageSelectedTabIndex = 1; // 日志 tab// Server not running, ensure logs are editable/readableLogIsReadOnly = false;// Sharing remains disabled when server failed to startShareTabEnabled = false;return;}// Check HTTPS port availability when SSL is enabledif (EnableHttps && IsPortInUse(HttpsPort)){LogContent += $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} HTTPS 端口 {HttpsPort} 已被占用,启动被拒绝。{Environment.NewLine}";SelectedTabIndex = 1;LogIsReadOnly = false;ShareTabEnabled = false;return;}Directory.CreateDirectory(SourceDir);// If application started with --debug-resource, prefer HtmlDebugServerstring debugRes = null;var app = System.Windows.Application.Current as App;if (app != null)debugRes = app.DebugResourcePath;var virtualDirs = _config.VirtualDirectories ?? new List<VirtualDirectoryInfo>();var authService = new AuthService(_config.Users ?? new List<UserAccount>());if (UseWebServer){FileServer = new StaticWebHostServer(ListenPort, SourceDir, true, EnableUpload, virtualDirs, authService,EnableHttps, HttpsPort, debugRes);}else{FileServer = new DefaultFileServer(ListenPort, SourceDir, true, EnableUpload, virtualDirs, authService,EnableHttps, HttpsPort, debugRes);}FileServer.LogGenerated += FileServer_LogGenerated;FileServer.NewReqeustIn += FileServer_NewReqeustIn;FileServer.RequestOut += FileServer_RequestOut;// 传递预览扩展名、站点名称、站点Logo、认证开关等配置到服务器if (FileServer is HttpFileServerBase hfsBase){hfsBase.EnableAuth = EnableAuth;hfsBase.StrictAuthMode = StrictAuthMode;hfsBase.PreviewImageExtensions = _config.PreviewImageExtensions?.ToList();hfsBase.PreviewTextExtensions = _config.PreviewTextExtensions?.ToList();hfsBase.SiteName = SiteName;hfsBase.SiteLogoPath = _config.SiteLogoPath ?? "";hfsBase.FaviconPath = _config.FaviconPath ?? "";}Status = ServerStatus.Starting;FileServer.Start();var ips = IPHelper.GetAllLocalIP();foreach (var ip in ips){if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork){LogContent += $"http://{ip}:{ListenPort}/{Environment.NewLine}";if (EnableHttps){LogContent += $"https://{ip}:{HttpsPort}/{Environment.NewLine}";}}else if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6){var ipstr = ip.ToString();if (ipstr.Contains("%"))ipstr = ipstr.Substring(0, ipstr.IndexOf("%"));LogContent += $"http://[{ipstr}]:{ListenPort}/{Environment.NewLine}";if (EnableHttps){LogContent += $"https://[{ipstr}]:{HttpsPort}/{Environment.NewLine}";}}}IsRunning = true;Status = ServerStatus.Running;// Ensure share info (QR and text) reflect the currently active portUpdateShareInfo();CommandStartServer?.RaiseCanExecuteChanged();CommandStopServer?.RaiseCanExecuteChanged();// Switch UI: show logs tab, enable share tab, make logs read-onlySelectedTabIndex = 1; // 日志 tabShareTabEnabled = true;LogIsReadOnly = true;}private void OnRequestStopServer(){if (!IsRunning)return;Status = ServerStatus.Stoping;FileServer.Stop();FileServer.LogGenerated -= FileServer_LogGenerated;FileServer.NewReqeustIn -= FileServer_NewReqeustIn;FileServer.RequestOut -= FileServer_RequestOut;// release reference to allow new server instance with different portFileServer = null;// Refresh share info to clear/reflect stopped stateUpdateShareInfo();IsRunning = false;Status = ServerStatus.Stopped;CommandStartServer?.RaiseCanExecuteChanged();CommandStopServer?.RaiseCanExecuteChanged();// Switch UI: show config tab, disable share tab, make logs editable/readableSelectedTabIndex = 0; // 配置 tabShareTabEnabled = false;LogIsReadOnly = false;}private void OnToggleTheme(){if (ThemeMode == "Light") ThemeMode = "Dark";else if (ThemeMode == "Dark") ThemeMode = "System";else ThemeMode = "Light";ApplyThemeResources();// 实时保存配置_config.ThemeMode = ThemeMode;_cfgSrv.SaveConfig(_config);}private void OnAddVirtualDir(){VirtualDirectoryItems.Add(new VirtualDirectoryInfo{Name = "NewShare",PhysicalPath = @"C:\",Description = "",AllowUpload = false});ApplyVirtualDirectoriesToServer();RefreshVirtualDirDisplay();}private void OnRemoveVirtualDir(){if (SelectedVirtualDirectoryItem != null){VirtualDirectoryItems.Remove(SelectedVirtualDirectoryItem);SelectedVirtualDirectoryItem = null;ApplyVirtualDirectoriesToServer();RefreshVirtualDirDisplay();}}private void OnAddUser(){UserItems.Add(new UserAccount{Username = "newuser",Password = "password",AllowedVirtualDirs = null,CanUpload = true});}private void OnRemoveUser(){if (SelectedUserItem != null){UserItems.Remove(SelectedUserItem);SelectedUserItem = null;}}private void OnApplyUsers(){var users = UserItems.ToList();// 持久化到配置文件_config.Users = users;_cfgSrv.SaveConfig(_config);// 热更新运行中的服务器if (IsRunning && FileServer is HttpFileServerBase hfs){hfs.UpdateUsers(users);LogContent += $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} 用户配置已热更新{Environment.NewLine}";}}private void OnApplyVirtualDirs(){ApplyVirtualDirectoriesToServer();RefreshVirtualDirDisplay();}/// <summary>/// 刷新虚拟目录 DataGrid 显示,使属性变更即时反映到界面/// </summary>public void RefreshVirtualDirDisplay(){var view = System.Windows.Data.CollectionViewSource.GetDefaultView(VirtualDirectoryItems);view?.Refresh();}/// <summary>/// 将当前虚拟目录配置推送到运行中的服务器,并持久化到配置文件/// </summary>private void ApplyVirtualDirectoriesToServer(){var vdirs = VirtualDirectoryItems.ToList();// 同步到配置对象并保存文件,确保下次启动时生效_config.VirtualDirectories = vdirs;_cfgSrv.SaveConfig(_config);if (IsRunning && FileServer is HttpFileServerBase hfs){hfs.UpdateVirtualDirectories(vdirs);LogContent += $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} 虚拟目录配置已热更新{Environment.NewLine}";}UpdateShareInfo();}private void UpdateShareInfo(){// Ensure updates happen on the UI threadvar uiDispatcher = Dispatcher ?? Application.Current?.Dispatcher;Action work = () =>{if (SelectedNetworkAdapter == null){IPv4QrImage = null;IPv6QrImage = null;IPv4Text = string.Empty;IPv6Text = string.Empty;return;}// Determine protocol and port based on SSL settingstring scheme = EnableHttps && IsRunning ? "https" : "http";int displayPort = EnableHttps && IsRunning ? HttpsPort : ListenPort;// Build URLsif (!string.IsNullOrWhiteSpace(SelectedNetworkAdapter.IPv4)){var url = $"{scheme}://{SelectedNetworkAdapter.IPv4}:{displayPort}/";IPv4Text = url;IPv4QrImage = GenerateQrImage(url);}else{IPv4Text = string.Empty;IPv4QrImage = null;}if (!string.IsNullOrWhiteSpace(SelectedNetworkAdapter.IPv6)){var ip = SelectedNetworkAdapter.IPv6;if (ip.Contains("%")) ip = ip.Substring(0, ip.IndexOf('%'));var url = $"{scheme}://[{ip}]:{displayPort}/";IPv6Text = url;IPv6QrImage = GenerateQrImage(url);}else{IPv6Text = string.Empty;IPv6QrImage = null;}};if (uiDispatcher != null && !uiDispatcher.CheckAccess())uiDispatcher.BeginInvoke(work);elsework();}#endregion Methods}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。