using System; using System.ComponentModel; using System.IO; using System.Numerics; using System.Runtime.CompilerServices; namespace OpenTap.Addin.Util { public class LocationString : INotifyPropertyChanged { #region ... public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); UserInput.NotifyChanged(this, propertyName); } protected void Set([CallerMemberName] string name = null) { OnPropertyChanged(name); } protected void Set(ref T old, T @new, [CallerMemberName] string propertyName = null) { old = @new; if (propertyName != null) { Set(propertyName); } } #endregion private string relativeLocation = string.Empty; public string RelativeLocation { get => relativeLocation; set { Set(ref relativeLocation, value); } } private string absoluteLocation = string.Empty; public string AbsoluteLocation { get => absoluteLocation; set { Set(ref absoluteLocation, value); } } private static string AppendDirectorySeparator(string path) { // 如果是目录路径,确保以分隔符结尾 if (!path.EndsWith(Path.DirectorySeparatorChar.ToString()) && !path.EndsWith(Path.AltDirectorySeparatorChar.ToString())) { // 检查是否是目录(简单判断:没有扩展名或明确是目录) if (Directory.Exists(path)) path += Path.DirectorySeparatorChar; } return path; } public static string GetRelativePath(string fromPath, string toPath) { // 获取绝对路径 fromPath = Path.GetFullPath(fromPath); toPath = Path.GetFullPath(toPath); // 如果路径不在同一根目录下(如 C:\ 和 D:\),无法计算相对路径 if (!string.Equals(Path.GetPathRoot(fromPath), Path.GetPathRoot(toPath), StringComparison.OrdinalIgnoreCase)) { return toPath; // 返回绝对路径 } // 使用 Uri 计算相对路径 Uri fromUri = new Uri(AppendDirectorySeparator(fromPath)); Uri toUri = new Uri(AppendDirectorySeparator(toPath)); Uri relativeUri = fromUri.MakeRelativeUri(toUri); string relativePath = Uri.UnescapeDataString(relativeUri.ToString()); // 转换为文件路径格式 relativePath = relativePath.Replace('/', Path.DirectorySeparatorChar); // 移除开头的分隔符(如果有) if (relativePath.StartsWith(Path.DirectorySeparatorChar.ToString())) relativePath = relativePath.Substring(1); return relativePath; } public static string GetAbsolutePath(string basePath, string relativePath) { if (string.IsNullOrEmpty(basePath)) { return relativePath; } string dirPath = Path.GetDirectoryName(basePath); string combinedPath = Path.Combine(dirPath, relativePath); return Path.GetFullPath(combinedPath); } public void Refresh(string basePath) { if (string.IsNullOrEmpty(basePath)) { return; } string path = LocationString.GetAbsolutePath(basePath, RelativeLocation); if (File.Exists(path)) { if (Path.IsPathRooted(RelativeLocation)) { RelativeLocation = LocationString.GetRelativePath(basePath, path); } AbsoluteLocation = path; return; } if (File.Exists(AbsoluteLocation)) { path = LocationString.GetRelativePath(basePath, AbsoluteLocation); RelativeLocation = path; return; } } public bool GetLocation(string basePath, out string location) { location = null; if (Path.IsPathRooted(RelativeLocation)) { if (File.Exists(RelativeLocation)) { location = RelativeLocation; return true; } } else { string path = GetAbsolutePath(basePath, RelativeLocation); if (File.Exists(path)) { location = path; return true; } } if (File.Exists(AbsoluteLocation)) { location = AbsoluteLocation; return true; } return false; } } }