Skip to content

Commit f3d0cf0

Browse files
committed
wpf: readd WPF UI/threading helpers
1 parent 018def6 commit f3d0cf0

File tree

1 file changed

+93
-0
lines changed
  • src/windows/Shared.UI.Windows

1 file changed

+93
-0
lines changed

src/windows/Shared.UI.Windows/Gui.cs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using System.Windows;
6+
using System.Windows.Controls;
7+
using Microsoft.Git.CredentialManager.UI.Controls;
8+
using Microsoft.Git.CredentialManager.UI.ViewModels;
9+
10+
namespace Microsoft.Git.CredentialManager.UI
11+
{
12+
public static class Gui
13+
{
14+
/// <summary>
15+
/// Present the user with a <see cref="Window"/>.
16+
/// </summary>
17+
/// <param name="windowCreator"><see cref="Window"/> factory.</param>
18+
/// <param name="parentHwnd">Parent window handle.</param>
19+
/// <returns>
20+
/// Returns `<see langword="true"/>` if the user completed the dialog; otherwise `<see langword="false"/>`
21+
/// if the user canceled or abandoned the dialog.
22+
/// </returns>
23+
public static Task ShowWindow(Func<Window> windowCreator, IntPtr parentHwnd)
24+
{
25+
return StartSTATask(() => ShowDialog(windowCreator(), parentHwnd));
26+
}
27+
28+
/// <summary>
29+
/// Present the user with a <see cref="DialogWindow"/>.
30+
/// </summary>
31+
/// <returns>
32+
/// Returns `<see langword="true"/>` if the user completed the dialog and the view model is valid;
33+
/// otherwise `<see langword="false"/>` if the user canceled or abandoned the dialog, or the view
34+
/// model is invalid.
35+
/// </returns>
36+
/// <param name="viewModel">Window view model.</param>
37+
/// <param name="contentCreator">Window content factory.</param>
38+
/// <param name="parentHwnd">Parent window handle.</param>
39+
public static Task ShowDialogWindow(WindowViewModel viewModel, Func<UserControl> contentCreator, IntPtr parentHwnd)
40+
{
41+
return ShowWindow(() => new DialogWindow(contentCreator()) { DataContext = viewModel }, parentHwnd);
42+
}
43+
44+
private static Task StartSTATask(Action action)
45+
{
46+
var completionSource = new TaskCompletionSource<object>();
47+
var thread = new Thread(() =>
48+
{
49+
try
50+
{
51+
action();
52+
completionSource.SetResult(null);
53+
}
54+
catch (Exception e)
55+
{
56+
completionSource.SetException(e);
57+
}
58+
});
59+
60+
thread.SetApartmentState(ApartmentState.STA);
61+
thread.Start();
62+
63+
return completionSource.Task;
64+
}
65+
66+
public static bool? ShowDialog(Window window, IntPtr parentHwnd)
67+
{
68+
// Zero is not a valid window handle
69+
if (parentHwnd == IntPtr.Zero)
70+
{
71+
return window.ShowDialog();
72+
}
73+
74+
// Set the parent window handle and ensure the dialog starts in the correct location
75+
new System.Windows.Interop.WindowInteropHelper(window).Owner = parentHwnd;
76+
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
77+
78+
const int ERROR_INVALID_WINDOW_HANDLE = 1400;
79+
80+
try
81+
{
82+
return window.ShowDialog();
83+
}
84+
catch (Win32Exception ex) when (ex.NativeErrorCode == ERROR_INVALID_WINDOW_HANDLE)
85+
{
86+
// The window handle given was invalid - clear the owner and show the dialog centered on the screen
87+
window.Owner = null;
88+
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
89+
return window.ShowDialog();
90+
}
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)