在我的UWP应用程序中,我需要不断地从WinForms(Win32)组件向UWP应用程序发送数据,反之亦然。但是,我的WinForms组件中有一个奇怪的错误。有时,在启动WinForm时,我在致电System.InvalidOperationException
时会收到await connection.SendMessageAsync(message)
说:A method was called at an unexpected time
其他时候,它会完美运行。
我的代码:
private async void SendToUWPVoidAsync(object content)
{
ValueSet message = new ValueSet();
if (content != "request") message.Add("content", content);
else message.Add(content as string, "");
#region SendToUWP
// if connection isn't inited
if (connection == null)
{
// init
connection = new AppServiceConnection();
connection.PackageFamilyName = Package.Current.Id.FamilyName;
connection.AppServiceName = "NotifyIconsUWP";
connection.ServiceClosed += Connection_ServiceClosed;
// attempt connection
AppServiceConnectionStatus connectionStatus = await connection.OpenAsync();
}
AppServiceResponse serviceResponse = await connection.SendMessageAsync(message);
// get response
if (serviceResponse.Message.ContainsKey("content"))
{
object newMessage = null;
serviceResponse.Message.TryGetValue("content", out newMessage);
// if message is an int[]
if (newMessage is int[])
{
// init field vars
int indexInArray = 0;
foreach (int trueorfalse in (int[])newMessage)
{
// set bool state based on index
switch (indexInArray)
{
case 0:
notifyIcon1.Visible = Convert.ToBoolean(trueorfalse);
break;
case 1:
notifyIcon2.Visible = Convert.ToBoolean(trueorfalse);
break;
case 2:
notifyIcon3.Visible = Convert.ToBoolean(trueorfalse);
break;
default:
break;
}
indexInArray++;
}
}
}
#endregion
}
这个方法的调用如下:
private void TCheckLockedKeys_Tick(object sender, EventArgs e)
{
...
if (statusesChanged)
{
// update all bools
bool1 = ...;
bool2 = ...;
bool3 = ...;
// build int[] from bool values
int[] statuses = new int[] { Convert.ToInt32(bool1), Convert.ToInt32(bool2), Convert.ToInt32(bool3) };
// update UWP sibling
SendToUWPVoidAsync(statuses);
}
// ask for new settings
SendToUWPVoidAsync("request");
}
TCheckLockedKeys_Tick.Interval
设置为250毫秒。
有没有办法在没有WinForm组件退出但仍然建立重要通信路径的情况下阻止或正确处理此异常?
有什么想法吗?
由于
答案 0 :(得分:0)
好的,我找到了解决方案。人们可能实际上称之为解决方法。
在我的WinForm中,我更改了代码如下:
AppServiceResponse serviceResponse = await connection.SendMessageAsync(message);
为:
AppServiceResponse serviceResponse = null;
try
{
// send message
serviceResponse = await connection.SendMessageAsync(message);
}
catch (Exception)
{
// exit
capsLockStatusNI.Visible = false;
numLockStatusNI.Visible = false;
scrollLockStatusNI.Visible = false;
Application.Exit();
}
我还更改了App.xaml.cs
文件中的代码:
private async void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
if (this.appServiceDeferral != null)
{
// Complete the service deferral.
this.appServiceDeferral.Complete();
}
}
到:
private async void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
if (reason == BackgroundTaskCancellationReason.SystemPolicy)
{
// WinForm called Application.Exit()
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
}
if (this.appServiceDeferral != null)
{
// Complete the service deferral.
this.appServiceDeferral.Complete();
}
}
我知道我所做的一切,从技术上来说,重新启动表格直到它成功,这不完全是解决它的正确方法。但是,它有效。
答案 1 :(得分:0)
基于
的一些建议参考Async/Await - Best Practices in Asynchronous Programming
除了事件处理程序之外,避免使用
async void
。比async Task
种方法更喜欢async void
种方法。
异步void会导致忘记,这会导致遇到问题,因为异常不会在正确的上下文中抛出。
Async void方法具有不同的错误处理语义。当异步任务或异步任务方法抛出异常时,将捕获该异常并将其放在Task对象上。使用async void方法时,没有Task对象,因此异步void方法抛出的任何异常都将直接在async void方法启动时处于活动状态的SynchronizationContext上引发。
假定在事件处理程序中调用该方法。然后重构该方法以使用async Task
private async Task SendToUWPVoidAsync(object content) {
//...
}
并将事件处理程序更新为异步
private async void TCheckLockedKeys_Tick(object sender, EventArgs e) {
try {
//...
if (statusesChanged) {
// update all bools
bool1 = ...;
bool2 = ...;
bool3 = ...;
// build int[] from bool values
int[] statuses = new int[] { Convert.ToInt32(bool1), Convert.ToInt32(bool2), Convert.ToInt32(bool3) };
// update UWP sibling
await SendToUWPVoidAsync(statuses);
}
// ask for new settings
await SendToUWPVoidAsync("request");
}catch {
//...handle error appropriately
}
}
还应该允许捕获任何异常,如上例所示。