await Task.WhenAll 自动关闭程序
await Task.WhenAll automatically close the program
我有一个方法可以对 Chromium 浏览器进行初始化。 运行 两个异步方法后,程序自动关闭。我是不是用错了Task.WhenAll
?
这里是程序的入口点:
Start.cs
static class Start
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Initializer.Start();
}
}
Initializer.cs
public static class Initializer
{
public static async void Start()
{
// The task that automatically close the program.
Task<bool> chromiumInitTask = ChromiumInfo.InitializeAsync();
await chromiumInitTask;
Task webviewInitTask = WebViewInfo.InitializeAsync();
Task guiInitTask = GUIInfo.InitializeAsync();
HardwareManager.Initialize();
await webviewInitTask;
await guiInitTask;
GUIInfo.Layout.ChangeMainDisplay(ChromiumInfo.Browser);
Application.Run(GUIInfo.Layout.GetLayoutForm());
}
}
ChromiumInfo.cs
public static class ChromiumInfo
{
private static CefSettings _settings;
private static ChromiumWebBrowser _browser;
private static BrowserSettings _browserSettings;
private static Dictionary<string, bool> _initTasks = new Dictionary<string, bool>()
{
{ "Settings", false },
{ "Browser Settings", false },
{ "Browser", false },
{ "Cef", false }
};
private static KeyboardHandler _keyboardHandler;
/// <summary>
/// An setting which using on initialize.
/// </summary>
public static CefSettings Setting => _settings;
/// <summary>
/// Representing a browser which can be show in UI.
/// </summary>
public static ChromiumWebBrowser Browser => _browser;
/// <summary>
/// A keyboard handler which handle various keyboard events.
/// </summary>
public static KeyboardHandler KeyboardHandler => _keyboardHandler;
/// <summary>
/// Occur when request to change the browser.
/// </summary>
public static event RequestChangeBrowserEventHandler RequestChangeBrowser;
/// <summary>
/// Initialize all Chromium components in asynchronously.
/// </summary>
/// <param name="initAllScripts">Indicate should initialize all scripts contain in the root script directory.</param>
/// <returns>Return a task can be awaited. True means sucess. Otherwise, return false.</returns>
public static async Task<bool> InitializeAsync(bool initAllScripts = true)
{
Task settingInit = SettingsInitializeAsync();
Task browserSettingInit = BrowserSettingsInitializeAsync();
// The below line that automatically close the program.
await Task.WhenAll(settingInit, browserSettingInit);
Task cefInit = Cef.InitializeAsync(_settings);
await cefInit;
_initTasks["Cef"] = true;
Task browserInit = BrowserInitializeAsync();
await browserInit;
Task eventInit = EventInitializeAsync();
await eventInit;
Task scriptInit = ScriptInitializeAsync();
await scriptInit;
return _initTasks.Values.Where(it => it).Count() == _initTasks.Count;
}
private static async Task SettingsInitializeAsync()
{
try
{
_settings = new CefSettings();
_settings.CommandLineArgsDisabled = false;
_settings.CefCommandLineArgs.Clear();
_settings.CefCommandLineArgs.Add("enable-3d-apis", "1");
_settings.CefCommandLineArgs.Add("enable-webgl-draft-extensions", "1");
_settings.CefCommandLineArgs.Add("enable-gpu", "1");
_settings.CefCommandLineArgs.Add("enable-webgl", "1");
_settings.CefCommandLineArgs.Add("gpu_compositing", "1");
_settings.CefCommandLineArgs.Add("ignore-gpu-blocklist", "1");
await Task.Delay(1000).ConfigureAwait(false);
_initTasks["Settings"] = true;
}
catch (Exception e)
{
SystemLog.Write(e);
}
}
private static async Task BrowserSettingsInitializeAsync()
{
try
{
_browserSettings = new BrowserSettings();
_browserSettings.WebGl = CefState.Enabled;
await Task.Delay(1000).ConfigureAwait(false);
_initTasks["Browser Settings"] = true;
}
catch (Exception e)
{
SystemLog.Write(e);
}
}
private static async Task BrowserInitializeAsync()
{
try
{
_browser = new ChromiumWebBrowser(Properties.Settings.Default.DefaultURL);
_browser.BrowserSettings = _browserSettings;
_browser.Dock = System.Windows.Forms.DockStyle.Fill;
await Task.Delay(1000).ConfigureAwait(false);
_initTasks["Browser"] = true;
}
catch (Exception e)
{
SystemLog.Write(e);
}
}
private static async Task EventInitializeAsync()
{
KeyboardHandler keyboardHandler = new KeyboardHandler();
WebCommandHandler commandHandler = new WebCommandHandler();
_browser.ConsoleMessage += keyboardHandler.Handle;
_browser.ConsoleMessage += commandHandler.Handle;
_browser.AddressChanged += Custom_AddressChanged;
_keyboardHandler = keyboardHandler;
await Task.Delay(1000).ConfigureAwait(false);
}
private static async Task ScriptInitializeAsync()
{
string scriptPath = $@"{ProgramInfo.RootPath}\scripts";
if (Directory.Exists(scriptPath))
{
var files = Directory.GetFiles(scriptPath, "*.js");
files?.ToList().ForEach(f => _browser.GetMainFrame().ExecuteJavaScriptAsync(f, _browser.Address));
}
await Task.Delay(1000).ConfigureAwait(false);
}
private static void Custom_AddressChanged(object sender, AddressChangedEventArgs e)
{
var wv2SiteCount = Properties.Settings.Default.WebToWV2.Cast<string>()
.Where(s => s.IndexOf(e.Address) >= 0).Count();
if (wv2SiteCount > 0)
{
WebViewInfo.Navigate(e.Address);
RequestChangeBrowser?.Invoke(null, new RequestChangeBrowserEventArgs(WebViewInfo.Browser));
}
}
}
这是因为 await
的工作原理。当await
作用于不完整的Task
时,它returns。所以你的程序是这样工作的:
Main
运行,并调用 Initializer.Start()
Initializer.Start()
运行并调用 ChromiumInfo.InitializeAsync()
ChromiumInfo.InitializeAsync()
运行直到它调用 await Task.WhenAll(settingInit, browserSettingInit)
- 因为
Task.WhenAll
returns一个不完整Task
,ChromiumInfo.InitializeAsync()
returns自身不完整Task
而执行returns Initializer.Start()
.
Initializer.Start()
中的await
看到不完整Task
和returns自己不完整Task
并执行returns到Main()
.
- 因为
Main()
没有作用于Initializer.Start()
返回的Task
,所以继续执行到下一行,也就是程序的结尾。
解决方案相当简单:将您的 Main
方法更改为 async
并使用 await
.
public static async Task Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
await Initializer.Start();
}
使Main()
async
的能力是a feature introduced in C# 7.1。
我有一个方法可以对 Chromium 浏览器进行初始化。 运行 两个异步方法后,程序自动关闭。我是不是用错了Task.WhenAll
?
这里是程序的入口点:
Start.cs
static class Start
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Initializer.Start();
}
}
Initializer.cs
public static class Initializer
{
public static async void Start()
{
// The task that automatically close the program.
Task<bool> chromiumInitTask = ChromiumInfo.InitializeAsync();
await chromiumInitTask;
Task webviewInitTask = WebViewInfo.InitializeAsync();
Task guiInitTask = GUIInfo.InitializeAsync();
HardwareManager.Initialize();
await webviewInitTask;
await guiInitTask;
GUIInfo.Layout.ChangeMainDisplay(ChromiumInfo.Browser);
Application.Run(GUIInfo.Layout.GetLayoutForm());
}
}
ChromiumInfo.cs
public static class ChromiumInfo
{
private static CefSettings _settings;
private static ChromiumWebBrowser _browser;
private static BrowserSettings _browserSettings;
private static Dictionary<string, bool> _initTasks = new Dictionary<string, bool>()
{
{ "Settings", false },
{ "Browser Settings", false },
{ "Browser", false },
{ "Cef", false }
};
private static KeyboardHandler _keyboardHandler;
/// <summary>
/// An setting which using on initialize.
/// </summary>
public static CefSettings Setting => _settings;
/// <summary>
/// Representing a browser which can be show in UI.
/// </summary>
public static ChromiumWebBrowser Browser => _browser;
/// <summary>
/// A keyboard handler which handle various keyboard events.
/// </summary>
public static KeyboardHandler KeyboardHandler => _keyboardHandler;
/// <summary>
/// Occur when request to change the browser.
/// </summary>
public static event RequestChangeBrowserEventHandler RequestChangeBrowser;
/// <summary>
/// Initialize all Chromium components in asynchronously.
/// </summary>
/// <param name="initAllScripts">Indicate should initialize all scripts contain in the root script directory.</param>
/// <returns>Return a task can be awaited. True means sucess. Otherwise, return false.</returns>
public static async Task<bool> InitializeAsync(bool initAllScripts = true)
{
Task settingInit = SettingsInitializeAsync();
Task browserSettingInit = BrowserSettingsInitializeAsync();
// The below line that automatically close the program.
await Task.WhenAll(settingInit, browserSettingInit);
Task cefInit = Cef.InitializeAsync(_settings);
await cefInit;
_initTasks["Cef"] = true;
Task browserInit = BrowserInitializeAsync();
await browserInit;
Task eventInit = EventInitializeAsync();
await eventInit;
Task scriptInit = ScriptInitializeAsync();
await scriptInit;
return _initTasks.Values.Where(it => it).Count() == _initTasks.Count;
}
private static async Task SettingsInitializeAsync()
{
try
{
_settings = new CefSettings();
_settings.CommandLineArgsDisabled = false;
_settings.CefCommandLineArgs.Clear();
_settings.CefCommandLineArgs.Add("enable-3d-apis", "1");
_settings.CefCommandLineArgs.Add("enable-webgl-draft-extensions", "1");
_settings.CefCommandLineArgs.Add("enable-gpu", "1");
_settings.CefCommandLineArgs.Add("enable-webgl", "1");
_settings.CefCommandLineArgs.Add("gpu_compositing", "1");
_settings.CefCommandLineArgs.Add("ignore-gpu-blocklist", "1");
await Task.Delay(1000).ConfigureAwait(false);
_initTasks["Settings"] = true;
}
catch (Exception e)
{
SystemLog.Write(e);
}
}
private static async Task BrowserSettingsInitializeAsync()
{
try
{
_browserSettings = new BrowserSettings();
_browserSettings.WebGl = CefState.Enabled;
await Task.Delay(1000).ConfigureAwait(false);
_initTasks["Browser Settings"] = true;
}
catch (Exception e)
{
SystemLog.Write(e);
}
}
private static async Task BrowserInitializeAsync()
{
try
{
_browser = new ChromiumWebBrowser(Properties.Settings.Default.DefaultURL);
_browser.BrowserSettings = _browserSettings;
_browser.Dock = System.Windows.Forms.DockStyle.Fill;
await Task.Delay(1000).ConfigureAwait(false);
_initTasks["Browser"] = true;
}
catch (Exception e)
{
SystemLog.Write(e);
}
}
private static async Task EventInitializeAsync()
{
KeyboardHandler keyboardHandler = new KeyboardHandler();
WebCommandHandler commandHandler = new WebCommandHandler();
_browser.ConsoleMessage += keyboardHandler.Handle;
_browser.ConsoleMessage += commandHandler.Handle;
_browser.AddressChanged += Custom_AddressChanged;
_keyboardHandler = keyboardHandler;
await Task.Delay(1000).ConfigureAwait(false);
}
private static async Task ScriptInitializeAsync()
{
string scriptPath = $@"{ProgramInfo.RootPath}\scripts";
if (Directory.Exists(scriptPath))
{
var files = Directory.GetFiles(scriptPath, "*.js");
files?.ToList().ForEach(f => _browser.GetMainFrame().ExecuteJavaScriptAsync(f, _browser.Address));
}
await Task.Delay(1000).ConfigureAwait(false);
}
private static void Custom_AddressChanged(object sender, AddressChangedEventArgs e)
{
var wv2SiteCount = Properties.Settings.Default.WebToWV2.Cast<string>()
.Where(s => s.IndexOf(e.Address) >= 0).Count();
if (wv2SiteCount > 0)
{
WebViewInfo.Navigate(e.Address);
RequestChangeBrowser?.Invoke(null, new RequestChangeBrowserEventArgs(WebViewInfo.Browser));
}
}
}
这是因为 await
的工作原理。当await
作用于不完整的Task
时,它returns。所以你的程序是这样工作的:
Main
运行,并调用Initializer.Start()
Initializer.Start()
运行并调用ChromiumInfo.InitializeAsync()
ChromiumInfo.InitializeAsync()
运行直到它调用await Task.WhenAll(settingInit, browserSettingInit)
- 因为
Task.WhenAll
returns一个不完整Task
,ChromiumInfo.InitializeAsync()
returns自身不完整Task
而执行returnsInitializer.Start()
. Initializer.Start()
中的await
看到不完整Task
和returns自己不完整Task
并执行returns到Main()
.- 因为
Main()
没有作用于Initializer.Start()
返回的Task
,所以继续执行到下一行,也就是程序的结尾。
解决方案相当简单:将您的 Main
方法更改为 async
并使用 await
.
public static async Task Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
await Initializer.Start();
}
使Main()
async
的能力是a feature introduced in C# 7.1。