diff --git a/src/Views/Controls/FolderDialog.cs b/src/Views/Controls/FolderDialog.cs
new file mode 100644
index 00000000..a048727d
--- /dev/null
+++ b/src/Views/Controls/FolderDialog.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace SourceGit.Views.Controls {
+
+ [SuppressUnmanagedCodeSecurity]
+ internal delegate Int32 BrowseCallbackProc(IntPtr hwnd, Int32 msg, IntPtr lParam, IntPtr lpData);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ [SuppressUnmanagedCodeSecurity]
+ internal class BrowseInfo {
+ public IntPtr hwndOwner;
+ public IntPtr pidlRoot;
+ public IntPtr pszDisplayName;
+ public String lpszTitle;
+ public Int32 ulFlags;
+ public BrowseCallbackProc lpfn;
+ public IntPtr lParam;
+ public Int32 iImage;
+ }
+
+ ///
+ /// Win32 API封装(user32.dll)
+ ///
+ [SuppressUnmanagedCodeSecurity]
+ internal static class User32 {
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ public static extern IntPtr SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, String lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ public static extern IntPtr SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam);
+ }
+
+ ///
+ /// Win32 API封装(ole32.dll)
+ ///
+ [SuppressUnmanagedCodeSecurity]
+ internal static class Ole32 {
+ [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, SetLastError = true)]
+ internal static extern void CoTaskMemFree(IntPtr pv);
+ }
+
+ ///
+ /// Win32 API封装(shell32.dll)
+ ///
+ [SuppressUnmanagedCodeSecurity]
+ internal static class Shell32 {
+ [DllImport("shell32.dll")]
+ public static extern Int32 SHGetSpecialFolderLocation(IntPtr hwnd, Int32 csidl, ref IntPtr ppidl);
+
+ [DllImport("shell32.dll", CharSet = CharSet.Auto)]
+ public static extern Boolean SHGetPathFromIDList(IntPtr pidl, IntPtr pszPath);
+
+ [DllImport("shell32.dll", CharSet = CharSet.Auto)]
+ public static extern IntPtr SHBrowseForFolder([In] BrowseInfo lpbi);
+ }
+
+ ///
+ /// 调用WindowsAPI打开对话目录对话框
+ ///
+ public class FolderDialog : Microsoft.Win32.CommonDialog {
+ ///
+ /// 描述信息
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// 选中的目录
+ ///
+ public string SelectedPath { get; private set; }
+
+ public FolderDialog(string descKey) {
+ Description = App.Text(descKey);
+ SelectedPath = string.Empty;
+ }
+
+ public override void Reset() {
+ Description = string.Empty;
+ SelectedPath = string.Empty;
+ }
+
+ protected override bool RunDialog(IntPtr hwndOwner) {
+ IntPtr ppidl = IntPtr.Zero;
+ Shell32.SHGetSpecialFolderLocation(hwndOwner, (Int32)Environment.SpecialFolder.Desktop, ref ppidl);
+ if (ppidl == IntPtr.Zero) {
+ Shell32.SHGetSpecialFolderLocation(hwndOwner, 0, ref ppidl);
+ if (ppidl == IntPtr.Zero) {
+ Models.Exception.Raise("Failed to open folder dialog!!!");
+ return false;
+ }
+ }
+
+ BrowseCallbackProc callback = new BrowseCallbackProc(BrowseCallbackHandler);
+ IntPtr displayName = Marshal.AllocHGlobal(260 * Marshal.SystemDefaultCharSize);
+ bool ok = false;
+ try {
+ var info = new BrowseInfo();
+ info.pidlRoot = ppidl;
+ info.hwndOwner = hwndOwner;
+ info.pszDisplayName = displayName;
+ info.lpszTitle = Description;
+ info.ulFlags = 0x0040;
+ info.lpfn = callback;
+ info.lParam = IntPtr.Zero;
+ info.iImage = 0;
+
+ IntPtr result = Shell32.SHBrowseForFolder(info);
+ if (result != IntPtr.Zero) {
+ IntPtr pathPtr = Marshal.AllocHGlobal(260 * Marshal.SystemDefaultCharSize);
+ Shell32.SHGetPathFromIDList(result, pathPtr);
+
+ if (pathPtr != IntPtr.Zero) {
+ SelectedPath = Marshal.PtrToStringAuto(pathPtr);
+ ok = true;
+ Marshal.FreeHGlobal(pathPtr);
+ }
+
+ Ole32.CoTaskMemFree(result);
+ }
+ } finally {
+ Ole32.CoTaskMemFree(ppidl);
+ if (displayName != IntPtr.Zero) Marshal.FreeHGlobal(displayName);
+ callback = null;
+ }
+
+ return ok;
+ }
+
+ private Int32 BrowseCallbackHandler(IntPtr hwnd, Int32 msg, IntPtr lParam, IntPtr lpData) {
+ switch (msg) {
+ case 1:
+ if (!string.IsNullOrEmpty(SelectedPath)) {
+ Int32 flag = Marshal.SystemDefaultCharSize == 1 ? 1126 : 1127;
+ User32.SendMessage(new HandleRef(null, hwnd), flag, 1, SelectedPath);
+ }
+ break;
+ case 2:
+ if (lParam != IntPtr.Zero) {
+ IntPtr pathPtr = Marshal.AllocHGlobal(260 * Marshal.SystemDefaultCharSize);
+ bool flag = Shell32.SHGetPathFromIDList(lParam, pathPtr);
+ Marshal.FreeHGlobal(pathPtr);
+ User32.SendMessage(new HandleRef(null, hwnd), 1125, 0, flag ? 1 : 0);
+ }
+ break;
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/src/Views/FolderBrowser.xaml b/src/Views/FolderBrowser.xaml
deleted file mode 100644
index 57e24a4e..00000000
--- a/src/Views/FolderBrowser.xaml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Views/FolderBrowser.xaml.cs b/src/Views/FolderBrowser.xaml.cs
deleted file mode 100644
index e6fa12c1..00000000
--- a/src/Views/FolderBrowser.xaml.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using System;
-using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.IO;
-using System.Windows;
-
-namespace SourceGit.Views {
-
- ///
- /// 目录选择对话框
- ///
- public partial class FolderBrowser : Window {
-
- ///
- /// 目录树节点.
- ///
- public class Node : INotifyPropertyChanged {
- public string Name { get; set; }
- public string Path { get; set; }
- public ObservableCollection Children { get; set; }
- public event PropertyChangedEventHandler PropertyChanged;
-
- public Node(string name, string path) {
- Name = name;
- Path = path;
- Children = new ObservableCollection();
- }
-
- public void CollectChildren() {
- Children.Clear();
-
- try {
- var dir = new DirectoryInfo(Path);
- var subs = dir.GetDirectories();
-
- foreach (var sub in subs) {
- if ((sub.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) continue;
- Children.Add(new Node(sub.Name, sub.FullName));
- }
- } catch { }
-
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Children"));
- }
- }
-
- public string Description { get; set; }
- public ObservableCollection Nodes { get; set; }
-
- public FolderBrowser(string description, Action onOK) {
- Description = description;
- Nodes = new ObservableCollection();
-
- var drives = DriveInfo.GetDrives();
- foreach (var d in drives) {
- var node = new Node(d.Name, d.Name);
- node.CollectChildren();
- Nodes.Add(node);
- }
-
- InitializeComponent();
-
- btnSure.Click += (o, e) => {
- if (tree.Selected.Count == 0) return;
- var node = tree.Selected[0] as Node;
- onOK?.Invoke(node.Path);
- Close();
- };
- }
-
- public static void Open(Window owner, string description, Action onOK) {
- var dialog = new FolderBrowser(description, onOK);
- if (owner == null) dialog.Owner = Application.Current.MainWindow;
- else dialog.Owner = owner;
- dialog.ShowDialog();
- }
-
- private void OnTreeNodeExpanded(object sender, RoutedEventArgs e) {
- var item = sender as Controls.TreeItem;
- if (item == null) return;
-
- var node = item.DataContext as Node;
- if (node == null) return;
-
- foreach (var c in node.Children) c.CollectChildren();
- e.Handled = true;
- }
-
- private void OnTreeSelectionChanged(object sender, RoutedEventArgs e) {
- if (tree.Selected.Count == 0) {
- btnSure.IsEnabled = false;
- txtSelected.Text = "NONE";
- } else {
- btnSure.IsEnabled = true;
- txtSelected.Text = (tree.Selected[0] as Node).Path;
- }
- }
-
- private void Quit(object sender, RoutedEventArgs e) {
- Close();
- }
- }
-}
diff --git a/src/Views/Popups/Clone.xaml.cs b/src/Views/Popups/Clone.xaml.cs
index 246ce290..2269fd30 100644
--- a/src/Views/Popups/Clone.xaml.cs
+++ b/src/Views/Popups/Clone.xaml.cs
@@ -54,10 +54,11 @@ namespace SourceGit.Views.Popups {
}
private void OnFolderSelectorClick(object sender, System.Windows.RoutedEventArgs e) {
- FolderBrowser.Open(null, App.Text("Clone.Folder.Placeholder"), path => {
- Folder = path;
+ var dialog = new Controls.FolderDialog("Clone.Folder.Placeholder");
+ if (dialog.ShowDialog() == true) {
+ Folder = dialog.SelectedPath;
txtFolder.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
- });
+ }
}
}
}
diff --git a/src/Views/Preference.xaml.cs b/src/Views/Preference.xaml.cs
index 19cedc54..8587f2fb 100644
--- a/src/Views/Preference.xaml.cs
+++ b/src/Views/Preference.xaml.cs
@@ -61,10 +61,11 @@ namespace SourceGit.Views {
}
private void SelectGitCloneDir(object sender, RoutedEventArgs e) {
- FolderBrowser.Open(this, App.Text("Preference.Dialog.GitDir"), path => {
- Models.Preference.Instance.Git.DefaultCloneDir = path;
+ var dialog = new Controls.FolderDialog("Preference.Dialog.GitDir");
+ if (dialog.ShowDialog() == true) {
+ Models.Preference.Instance.Git.DefaultCloneDir = dialog.SelectedPath;
txtGitCloneDir?.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
- });
+ }
}
private void SelectMergeTool(object sender, RoutedEventArgs e) {
diff --git a/src/Views/Widgets/Histories.xaml.cs b/src/Views/Widgets/Histories.xaml.cs
index c73e735a..e76cae16 100644
--- a/src/Views/Widgets/Histories.xaml.cs
+++ b/src/Views/Widgets/Histories.xaml.cs
@@ -342,9 +342,10 @@ namespace SourceGit.Views.Widgets {
var saveToPatch = new MenuItem();
saveToPatch.Header = App.Text("CommitCM.SaveAsPatch");
saveToPatch.Click += (o, e) => {
- FolderBrowser.Open(null, "Save patch to ...", saveTo => {
- new Commands.FormatPatch(repo.Path, commit.SHA, saveTo).Exec();
- });
+ var dialog = new Controls.FolderDialog("SaveFileTo");
+ if (dialog.ShowDialog() == true) {
+ new Commands.FormatPatch(repo.Path, commit.SHA, dialog.SelectedPath).Exec();
+ }
};
menu.Items.Add(saveToPatch);
menu.Items.Add(new Separator());
diff --git a/src/Views/Widgets/RevisionFiles.xaml.cs b/src/Views/Widgets/RevisionFiles.xaml.cs
index ae3c08a6..4e6fcb55 100644
--- a/src/Views/Widgets/RevisionFiles.xaml.cs
+++ b/src/Views/Widgets/RevisionFiles.xaml.cs
@@ -289,10 +289,11 @@ namespace SourceGit.Views.Widgets {
saveAs.Header = App.Text("SaveAs");
saveAs.IsEnabled = node.Type == Models.ObjectType.Blob;
saveAs.Click += (obj, ev) => {
- FolderBrowser.Open(null, App.Text("SaveFileTo"), saveTo => {
- var full = Path.Combine(saveTo, Path.GetFileName(node.Path));
+ var dialog = new Controls.FolderDialog("SaveFileTo");
+ if (dialog.ShowDialog() == true) {
+ var full = Path.Combine(dialog.SelectedPath, Path.GetFileName(node.Path));
new Commands.SaveRevisionFile(repo, node.Path, sha, full).Exec();
- });
+ }
ev.Handled = true;
};
diff --git a/src/Views/Widgets/Welcome.xaml.cs b/src/Views/Widgets/Welcome.xaml.cs
index 4d7e6a79..2b610fdb 100644
--- a/src/Views/Widgets/Welcome.xaml.cs
+++ b/src/Views/Widgets/Welcome.xaml.cs
@@ -47,7 +47,8 @@ namespace SourceGit.Views.Widgets {
#region FUNC_EVENTS
private void OnOpenClicked(object sender, RoutedEventArgs e) {
- FolderBrowser.Open(null, App.Text("Welcome.OpenOrInitDialog"), CheckAndOpen);
+ var dialog = new Controls.FolderDialog("Welcome.OpenOrInitDialog");
+ if (dialog.ShowDialog() == true) CheckAndOpen(dialog.SelectedPath);
}
private void OnCloneClicked(object sender, RoutedEventArgs e) {