Files
ShrlAlgoToolkit/ShrlAlgoToolkit.RevitAddins/Assists/WinDialogHelper.cs
2025-12-23 21:35:54 +08:00

315 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using Autodesk.Revit.DB;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Win32;
using ShrlAlgoToolkit.Core.Assists;
namespace ShrlAlgoToolkit.RevitAddins.Assists;
public static class WinDialogHelper
{
/// <summary>
/// 对话框过滤器
/// </summary>
/// <param name="filterName">过滤器的名称</param>
/// <param name="extensions">仅扩展名,*代表所有文件</param>
/// <returns></returns>
public static FileDialog SetFilter(this FileDialog dialog, string filterName, params string[] extensions)
{
if (extensions[0] == "*")
{
dialog.Filter = "所有文件(*)|*";
//return "所有文件(*)|*";
}
var str = string.Empty;
for (var i = 0; i < extensions.Length; i++)
{
var extension = extensions[i];
str += $"*.{extension}";
if (i < extensions.Length - 1)
{
str += ";";
}
}
dialog.Filter = $"{filterName}({str})|{str}";
return dialog;
//return $"{filterName}({str})|{str}";
}
/// <summary>
/// 释放命令行管理程序分配的ITEMIDLIST结构
/// Frees an ITEMIDLIST structure allocated by the Shell.
/// </summary>
/// <param name="pidlList"></param>
[DllImport("shell32.dll", ExactSpelling = true)]
private static extern void ILFree(IntPtr pidlList);
/// <summary>
/// 返回与指定文件路径关联的ITEMIDLIST结构。
/// Returns the ITEMIDLIST structure associated with a specified file path.
/// </summary>
/// <param name="pszPath"></param>
/// <returns></returns>
[DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern IntPtr ILCreateFromPathW(string pszPath);
/// <summary>
/// 打开一个Windows资源管理器窗口其中选择了特定文件夹中的指定项目。
/// Opens a Windows Explorer window with specified items in a particular folder selected.
/// </summary>
/// <param name="pidlList"></param>
/// <param name="cild"></param>
/// <param name="children"></param>
/// <param name="dwFlags"></param>
/// <returns></returns>
[DllImport("shell32.dll", ExactSpelling = true)]
private static extern int SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags);
/// <summary>
/// 打开或在现有目录并选中相应文件
/// </summary>
/// <param name="fileFullName"></param>
static public void OpenFolderAndSelectFile(string fileFullName)
{
if (string.IsNullOrEmpty(fileFullName))
throw new ArgumentNullException(nameof(fileFullName));
fileFullName = Path.GetFullPath(fileFullName);
var pidlList = ILCreateFromPathW(fileFullName);
if (pidlList == IntPtr.Zero) return;
try
{
Marshal.ThrowExceptionForHR(SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0));
}
finally
{
ILFree(pidlList);
}
}
/// <summary>
/// 新建一个资源管理器窗口并选中文件或文件夹
/// </summary>
/// <param name="fileOrFolderPath"></param>
public static void ExploreFile(string fileOrFolderPath)
{
//Process proc = new();
//proc.StartInfo.FileName = "explorer";
////打开资源管理器
//proc.StartInfo.Arguments = @"/select," + fileOrFolderPath;
////选中"notepad.exe"这个程序,即记事本
//proc.Start();
System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{fileOrFolderPath}\"");
}
/// <summary>
/// 选择文件
/// </summary>
/// <param name="title"></param>
/// <param name="extensions"></param>
/// <returns></returns>
public static string GetSelectedFilePath(string title, params string[] extensions)
{
OpenFileDialog dialog =
new()
{
CheckFileExists = true,
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
};
dialog.SetFilter(title, extensions);
return dialog.ShowDialog() == true ? dialog.FileName : null;
}
public static void UpdateViewDisplay(Autodesk.Revit.UI.PreviewControl _currentPreviewControl, System.Windows.Controls.Grid PreviewContainer, Document _backgroundDoc, View view, ViewDetailLevel detailLevel, DisplayStyle displayStyle)
{
if (_backgroundDoc == null || view == null) return;
_backgroundDoc.Invoke(
ts =>
{
try
{
view.DetailLevel = detailLevel;
view.DisplayStyle = displayStyle;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
});
// 2. 销毁旧控件
if (_currentPreviewControl != null)
{
PreviewContainer.Children.Clear();
_currentPreviewControl.Dispose();
_currentPreviewControl = null;
}
// 3. 创建新控件并加入 UI
_currentPreviewControl = new Autodesk.Revit.UI.PreviewControl(_backgroundDoc, view.Id);
PreviewContainer.Children.Add(_currentPreviewControl);
}
///// <summary>
///// 单选文件夹路径
///// </summary>
///// <returns></returns>
//public static string GetSelectedFolderPath()
//{
// var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog { Multiselect = false };
// var folderPath = dialog.ShowDialog() == true ? dialog.SelectedPath : null;
// return folderPath;
//}
///// <summary>
///// 多选文件夹路径
///// </summary>
///// <returns></returns>
//public static string[] GetSelectedFolderPaths()
//{
// var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog { Multiselect = true };
// return dialog.ShowDialog() == true ? dialog.SelectedPaths : null;
//}
/// <summary>
/// 打开窗口,非模态窗口置顶显示,默认非模态
/// </summary>
/// <returns></returns>
private static void ShowAhead(this Window window)
{
_ = new WindowInteropHelper(window) { Owner = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle };
window.Show();
}
public static void ShowModeless<T>(ObservableObject viewModel)
where T : Window, new()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
var view = SingletonViewAssist<T>.GetInstance(out var isNewCreate);
if (isNewCreate)
{
view.DataContext = viewModel;
view.ShowAhead();
}
view.Activate();
AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
//AssemblyLoaderHelpers loaderUtil = new(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//loaderUtil.HookAssemblyResolve();
//try
//{
// var view = SingletonViewAssist<Command>.GetInstance(out var isNewCreate);
// if (isNewCreate)
// {
// view.DataContext = viewModel;
// view.ShowAhead();
// }
// view.Activate();
//}
//catch (Exception ex)
//{
// LogAssist.ToLog($"{ex.Source}:{ex.StackTrace}");
//}
//finally
//{
// loaderUtil.UnhookAssemblyResolve();
//}
}
//private static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
//{
// if (!args.Name.Contains("Xaml.Behaviors"))
// {
// return null;
// }
// var assemblyFile = Path.Combine(
// Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
// "Microsoft.Xaml.Behaviors.dll"
// );
// return File.Exists(assemblyFile) ? Assembly.LoadFrom(assemblyFile) : null;
//}
private static Dictionary<Type, Window> _windows = [];
public static void ShowOrActivate<TWindow, TViewModel>(params object[] viewModelParams)
where TWindow : Window, new()
where TViewModel : class
{
var windowType = typeof(TWindow);
if (!_windows.ContainsKey(windowType) || _windows[windowType] == null)
{
//CloseAllWindowsExcept(windowType);
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
_windows[windowType] = new TWindow();
_windows[windowType].Closed += WindowClosed;
_windows[windowType].Closed += (_, _) => _windows[windowType] = null;
if (_windows[windowType].DataContext == null || !(_windows[windowType].DataContext is TViewModel))
{
if (viewModelParams.Length == 0)
{
_windows[windowType].DataContext = Activator.CreateInstance(typeof(TViewModel));
}
else
{
_windows[windowType].DataContext = Activator.CreateInstance(typeof(TViewModel), viewModelParams);
}
}
_ = new WindowInteropHelper(_windows[windowType]) { Owner = Process.GetCurrentProcess().MainWindowHandle };
_windows[windowType].Show();
}
else
{
_windows[windowType].Activate();
}
}
private static void WindowClosed(object sender, EventArgs e)
{
AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
StackFrame[] frames = new StackTrace().GetFrames();
if (frames == null)
{
return null;
}
string name = new AssemblyName(args.Name).Name;
List<string> list = new List<string>();
for (int i = 0; i < frames.Length; i++)
{
MethodBase method = frames[i].GetMethod();
if ((object)method.DeclaringType == null)
{
continue;
}
string directoryName = Path.GetDirectoryName(method.DeclaringType.Assembly.Location);
if (list.Contains(directoryName))
{
continue;
}
list.Add(directoryName);
foreach (string item in Directory.EnumerateFiles(directoryName, "*.dll"))
{
if (name == Path.GetFileNameWithoutExtension(item))
{
return Assembly.LoadFile(item);
}
}
}
return null;
}
}