使用Xamarin.Forms(对于iOS)我尝试实现功能,以等待用户确认已设置GeoLocation权限,然后再继续。C#AutoResetEvent没有发布
我试图做到这一点的方法是让线程等待,直到使用AutoResetEvent
触发事件。
主要的问题(我相信)位于下面的代码:
manager.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs args) => {
Console.WriteLine ("Authorization changed to: {0}", args.Status);
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
tcs.SetResult (args.Status == CLAuthorizationStatus.AuthorizedAlways || args.Status == CLAuthorizationStatus.AuthorizedWhenInUse);
} else {
tcs.SetResult (args.Status == CLAuthorizationStatus.Authorized);
}
_waitHandle.Set();
};
manager.Failed += (object sender, Foundation.NSErrorEventArgs e) => {
Console.WriteLine ("Authorization failed");
tcs.SetResult (false);
_waitHandle.Set();
};
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
manager.RequestWhenInUseAuthorization();
}
_waitHandle.WaitOne();
您可以在下面找到完整的类:
public class LocationManager : ILocationManager
{
static EventWaitHandle _waitHandle = new AutoResetEvent (false);
private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
public LocationManager()
{
}
public Task<bool> IsGeolocationEnabledAsync()
{
Console.WriteLine (String.Format("Avaible on device: {0}", CLLocationManager.LocationServicesEnabled));
Console.WriteLine (String.Format("Permission on device: {0}", CLLocationManager.Status));
if (!CLLocationManager.LocationServicesEnabled) {
tcs.SetResult (false);
} else if (CLLocationManager.Status == CLAuthorizationStatus.Denied || CLLocationManager.Status == CLAuthorizationStatus.Restricted) {
tcs.SetResult (false);
} else if (CLLocationManager.Status == CLAuthorizationStatus.NotDetermined) {
Console.WriteLine ("Waiting for authorisation");
CLLocationManager manager = new CLLocationManager();
manager.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs args) => {
Console.WriteLine ("Authorization changed to: {0}", args.Status);
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
tcs.SetResult (args.Status == CLAuthorizationStatus.AuthorizedAlways || args.Status == CLAuthorizationStatus.AuthorizedWhenInUse);
} else {
tcs.SetResult (args.Status == CLAuthorizationStatus.Authorized);
}
_waitHandle.Set();
};
manager.Failed += (object sender, Foundation.NSErrorEventArgs e) => {
Console.WriteLine ("Authorization failed");
tcs.SetResult (false);
_waitHandle.Set();
};
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
manager.RequestWhenInUseAuthorization();
}
_waitHandle.WaitOne();
Console.WriteLine (String.Format ("Auth complete: {0}", tcs.Task.Result));
} else {
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
tcs.SetResult (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse);
} else {
tcs.SetResult (CLLocationManager.Status == CLAuthorizationStatus.Authorized);
}
}
return tcs.Task;
}
}
它的工作原理,除了罚款,我想不通为什么manager.AuthorizationChanged
或manager.Failed
事件似乎永远不会被解雇,因此当状态为未确定时线程永远不会释放。
任何帮助或指针,不胜感激。
是的,代码根本没有任何意义 - 尤其是,考虑到'RequestWhenInUseAuthorization'必须在UI线程上调用。 所以他应该等待(隐式)在UI线程上的用户输入;例如。点击允许或取消。 – nullpotent
嘿,谢谢你的时间和详细的答案。我学到了很多 !我注意到的一件事是AutoResetEvent不再使用。我尝试在'C#等待事件完成'之后使用它。如果你不介意我再问一个问题,'result = await tcs.Task;'在这个上下文中是否做了类似于AutoResetEvent的事情,或者是否应该使用AutoResetEvent来防止多线程在使用? (请注意,我仍然是C#中的新手) – RVandersteen
@RVandersteen:_“does'result = await tcs.Task;'在此上下文中执行与AutoResetEvent类似的操作” - - 取决于您认为的“相似” 。它在类似的意义上是,该方法中的代码暂时“暂停”,直到事件发出信号。但是''AutoResetEvent''(ARE)通过使_thread_本身“暂停”来实现这一点,而使用'await'则不会。 –