等待静态回调完成

时间:2015-03-28 17:52:15

标签: c# asynchronous callback

我有一个场景:

  1. MyApp致电cameraCapture
  2. 会触发callbackFunction
  3. callbackFunction(我拍完照片)完成后,我做了更多的事情。
  4. 所以我必须在执行另一个函数之前等待callbackFunction完成。我怎么能这样做?

    这是我的代码:

    private static readonly Plustek_Camera.PFNCK_EVENT staticFnCamera = fnPFNCK_EVENT;
    
    public static bool fnPFNCK_EVENT(int iEvent, int iParam, IntPtr pUserData)
    {
       //capture picture and save to folder
    }
    
    //I implement callback start camera and fire a callback staticFnCamera
    
    var _status = CameraCtrl.Start(CameraCtrl.ScanMode, CameraCtrl.Resolution, CameraCtrl.ImageFormat, CameraCtrl.Alignment, staticFnCamera);
    
    //waiting for staticFnCamera complete make sure image produced 
    
     ReadPassPortText();
    

3 个答案:

答案 0 :(得分:1)

如果我理解正确,你有一些相机控件可以提供异步API来开始捕获图像,但你想同步等待该操作完成。

如果是这样,有很多不同的方法来完成你想要做的事情。一种方法是使用TaskCompletionSource

TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();

var _status = CameraCtrl.Start(CameraCtrl.ScanMode, CameraCtrl.Resolution,
    CameraCtrl.ImageFormat, CameraCtrl.Alignment,
    (iEvent, iParam, pUserData) =>
    {
        staticFnCamera(iEvent, iParam, pUserData);
        source.SetResult(true);
    });

//waiting for staticFnCamera complete make sure image produced 
await source.Task;
ReadPassPortText();

请注意,上述内容使用await,仅在async方法中有效。您没有提供足够的上下文来准确显示代码中的工作方式,但我强烈建议您按照上述方法操作。这将避免阻止当前运行的线程; async方法将在该点返回,让线程继续运行,并在操作完成时在ReadPassPortText();语句处恢复。

如果出于某种原因,您根本无法在方法中使用await,则只需执行source.Task.Wait();即可。当然,这将阻止该语句中当前正在执行的线程。

以上需要.NET 4.5。还有其他方法适用于早期版本的.NET,但您需要具体说明您的要求,以便值得尝试描述这些。


修改

由于您使用的是.NET 4.0,并且可能是Visual Studio 2010,因此上述内容对您而言并不适合“开箱即用”。一种选择是下载Visual Studio的Async CTP,它将为您提供启用上述功能的C#5.0编译器。但是,如果这对你来说不可行,那么另一个选择是通过用以下代码替换上面的最后两行来代表编译器做的事情:

source.Task.ContinueWith(task => ReadPassPortText(),
   TaskScheduler.FromCurrentSynchronizationContext());

这会将ReadPassPortText()的继续委托附加到Task的{​​{1}}对象,指定当前同步上下文作为用于实际运行延续的调度程序的源

该方法将在调用TaskCompletionSource之后返回(就像它在ContinueWith()版本中一样,除了在这里显式写出而不是编译器为你做的)。当await对象设置为已完成状态时,将执行先前注册的继续。

请注意,您的原始问题并不十分清楚。如果代码在UI线程中运行,那么使用Task很重要,并且将确保在UI线程中也执行继续。否则,您可能无法在FromCurrentSynchronizationContext()的调用中指定调度程序而离开。

答案 1 :(得分:0)

这演示了您可以使用的async-await模式。正如Peter Duniho在评论中指出的那样,您必须使模式适应您正在使用的API。 Try playing with it here at this fiddle了解这些事情是如何运作的。

using System;
using System.Threading.Tasks;

public class MyApp
{
    public static void Main()
    {
        Console.WriteLine("1. MyApp calls camera capture.");
        CameraCaptureAsync().Wait();
    }

    public async static Task CameraCaptureAsync()
    {
        Console.WriteLine("2. That calls callbackFunction");
        var task = CallbackFunction();
        Console.WriteLine("4. In the meantime.");
        Console.WriteLine("5. Do some other stuff. ");
        await task;
        Console.WriteLine("7. Process the " + task.Result);
        DoMoreStuff();
    }

    public async static Task<string> CallbackFunction()
    {
        Console.WriteLine("3. Which takes a picture.");
        await Task.Delay(100);
        Console.WriteLine("6. After the callback functions completes");
        return "Photograph";
    }

    public static void DoMoreStuff()
    {
        Console.WriteLine("8. Do more stuff.");
    }
}

答案 2 :(得分:0)

尝试一些实现回调等待后,我尝试通过添加另一个表单来捕获图像(frmSecond)来解决。

frmFirst调用frmSecond并在5到7秒内等待以确保捕获完成。

之后处理ReadPassPortText()

frmFirst Code:

  frmReadPassport frmReadPass = new frmReadPassport();
  frmReadPass.ShowDialog();
  ReadPassPortText();

frmSecondCode

    private CAMERACTRL CameraCtrl = null;
    //Add static for call from camera start , make sure this alive
    private static  Plustek_Camera.PFNCK_EVENT staticFnCamera ;
    public frmReadPassport()
    {
        InitializeComponent();
        staticFnCamera = fnPFNCK_EVENT;
    }
    Timer formClose = new Timer();
    private void frmReadPassport_Load(object sender, EventArgs e)
    {
        CaptureImages();
        formClose.Interval = 7000; // 7 sec
        formClose.Tick += new EventHandler(formClose_Tick);
        formClose.Start();
    }

    private void formClose_Tick(object sender, EventArgs e)
    {
        //free camera first
       // check if camera start then stop
        ReleaseResourceCamera();
        staticFnCamera =null;
        formClose.Stop();
        formClose.Tick -= new EventHandler(formClose_Tick);
        this.Dispose();
        this.Close();
    }    
   private void CaptureImages()
    {
        CameraCtrl = new CAMERACTRL();
        CameraCtrl.LoadCameraDll();
        CameraCtrl.GetDeviceList();
        String temp = CameraCtrl.GetParameter();
        CameraCtrl.Start(CameraCtrl.ScanMode,CameraCtrl.Resolution,CameraCtrl.ImageFormat, CameraCtrl.Alignment, staticFnCamera); 
   }

   public static bool fnPFNCK_EVENT(int iEvent, int iParam, IntPtr UserData)
   {
       captureImage();
       return true;
   }
}