在异步事件中处置对象C#WPF

时间:2017-11-13 14:42:59

标签: c# kinect kinect-sdk

我在Kinect SDK应用程序中使用WPF并使用DepthFrameReady事件进行操作。为了避免用户界面阻止我创建了事件async和即时等待"进行数据操作的函数。

立即在visual studio的输出窗口中获取消息:

  

警告:未放置imageFrame实例

我尝试了很多东西来处理DepthImageFrame(把逻辑置于using块内,当异步函数结束时回调等等......)但是在第一次调用之后它发送的是null,所以...

在async / await事件中处理对象的唯一方法是什么?

MyWindow.xaml.cs

private async void KinectSensorFound_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{

   // as suggested in Zoran Answer
   await Task.Run(() =>
            {
                using (DepthImageFrame DataDepthImageFrame = e.OpenDepthImageFrame())
                {
                    UpdateUserDepthInfo(DataDepthImageFrame);
                }

            });   
}


 public void UpdateUserDepthInfo(DepthImageFrame DataDepthImage)
        {
            var TimeNow = DateTime.Now;
            if ((DateTime.Now - PreviusTime).Milliseconds <= 50)
                return;

            syncronizationContext.Post(new SendOrPostCallback(o =>
            {
                if (chckbxDepthImage.IsChecked == true)
                {
                   chckbxColorImage.IsChecked = false; 
                   // This method is called in my bussines logic to do a transformation with the frame
                   BitmapSource DepthBitMapSource = Controller.getInfoOfDepthUser(DataDepthImage);
                   DepthCanvas.Background = new ImageBrush(DepthBitMapSource);
                }
                else
                {
                    DepthCanvas.Children.Clear();
                    DepthCanvas.Background = new SolidColorBrush(Colors.Transparent);
                }

                DepthUserInfo = Controller.DoGetInfoDepthUser(DataDepthImage);
                lblDepthUser.Content = string.Format("{0:0.00} mts", DepthUserInfo / 1000);

            }), DataDepthImage);
            PreviusTime = TimeNow;
        }

KinectHelper.cs

public BitmapSource getBitmapOfDepth(DepthImageFrame DataImageFrame)
{
    DepthImagePixel[] ImageDepth = new DepthImagePixel[0];
    int DepthDistance;
    depthReturnStruct DepthReturn = new depthReturnStruct();

    if (DataImageFrame != null)
    {
        ImageDepth = new DepthImagePixel[DataImageFrame.PixelDataLength];
        DataImageFrame.CopyDepthImagePixelDataTo(ImageDepth); // exception here

        //... other code
    }
    return bitmapDepth;
}

1 个答案:

答案 0 :(得分:0)

我的印象是你在混合责任。为了清楚起见,每个对象都应该拥有一个所有者 - 实例化它并将其处理掉的所有者。在您的解决方案中,这些是两个实体 - 构造DataDepthImageFrame的事件处理程序和执行工作的任务。

在我看来,启动任务的功能不应该构建图像框架,而是为它准备工厂函数。这将允许任务实例化和处置对象。通过这种方式,任务将完全负责该对象。

当然,如果您计划在关闭中捕获工厂,那么您甚至不需要它 - 您可以捕获事件参数e并直接在任务中使用它们。

private async void KinectSensorFound_DepthFrameReady(
    object sender, DepthImageFrameReadyEventArgs e)
{
   await Task.Run(
     () => 
     {
       using (DepthImageFrame DataDepthImageFrame = e.OpenDepthImageFrame())
       {
           UpdateUserDepthInfo(DataDepthImageFrame)
       }
   });
}

我无法重现您的场景,但我相信当任务开始运行时,来自事件参数的图像帧将在另一个线程中打开。