ZXing条码扫描器WinRT无法启动StartPreviewAsync()

时间:2013-11-08 09:53:21

标签: c# windows-8 winrt-xaml webcam zxing

我运行以下行来预览我的网络摄像头:

...
public MediaCapture VideoCaptureSource { get; set; }
var cameras = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

if (cameras.Count == 1)
{
  settings = new MediaCaptureInitializationSettings { VideoDeviceId = cameras[0].Id };
}
else
{
  settings = new MediaCaptureInitializationSettings { VideoDeviceId = cameras[1].Id };
}

await _mediaCapture.InitializeAsync(settings);
VideoCaptureSource = _mediaCapture;
await VideoCaptureSource.StartPreviewAsync();
...

这是我的XAML:

<Canvas Width="640" Height="360">
  <CaptureElement Source="{Binding VideoCaptureSource}" Visibility="{Binding VideoCaptureVisibility}" Width="640" Height="360" />
  <Image Source="{Binding CaptureImageSource}" Visibility="{Binding CaptureImageVisibility, FallbackValue=Collapsed}" Width="640" Height="360" />
</Canvas>

在我调用StartPreviewAsyn() - Method之前,一切正常。不幸的是,我只收到一条不太有用的错误消息:“请求的操作中发生意外错误。” 我试图在我的本地机器和模拟器上运行代码。有谁知道我做错了什么?

环境是Windows 8.1,Caliburn.Micro,ZXing.Net 0.12.0.0,VS 2013

1 个答案:

答案 0 :(得分:3)

我最近遇到了同样的问题。看起来绑定视频源非常棘手,因为您需要以正确的顺序初始化,设置和启动预览流。我使用附加属性修复了问题:

/// <summary>
/// This utility class provides an attached property that enables us to
/// bind the source of a <see cref="CaptureElement"/>.
/// </summary>
public static class VideoSourceBinding {

    public static MediaCapture GetVideoSource(DependencyObject obj) {
        return (MediaCapture) obj.GetValue(VideoSourceProperty);
    }

    public static void SetVideoSource(DependencyObject obj,
            MediaCapture value) {
        obj.SetValue(VideoSourceProperty, value);
    }

    public static readonly DependencyProperty VideoSourceProperty
        = DependencyProperty.RegisterAttached("VideoSource",
        typeof(MediaCapture),
        typeof(VideoSourceBinding),
        new PropertyMetadata(null, onVideoSourcePropertyChanged));

    private static async void onVideoSourcePropertyChanged(
            DependencyObject d, DependencyPropertyChangedEventArgs e) {
        Debug.Assert(d is CaptureElement);
        Debug.Assert(e.Property == VideoSourceBinding.VideoSourceProperty);

        CaptureElement preview = d as CaptureElement;

        if (d != null) {
            if (preview.Source != null) {
                // If another camera was attached before, stop it.
                await preview.Source.StopPreviewAsync();
            }

            try {
                preview.Source = (MediaCapture) e.NewValue;
            } catch {
                // The property change occurred before the the video source
                // was properly initialised. In this case, we ignore the
                // change and wait for the source to fire the event again
                // once the initialisation was completed.
                // Important: The source must actually change in order for
                // the event to be fired (the attached property will detect
                // if the same object was re-set) and ignore this.
                preview.Source = null;
            }

            if (preview.Source != null) {
                // Start the preview stream.
                await preview.Source.StartPreviewAsync();
            }
        }
    }
}

然后视频源绑定如下:

<CaptureElement u:VideoSourceBinding.VideoSource="{Binding VideoCapture}" />

请注意,您在视图模型中执行操作的顺序非常重要:

public class ViewModel : Screen {
    // Note: The sample uses a Caliburn Micro base class - this is, however, not
    // a requirement.

    public MediaCapture VideoCapture {
        get;
        private set;
    }

    /// <summary>
    /// Starts the video preview.
    /// </summary>
    /// <remarks>
    /// Call this method whenever it is necessary to (re-) start the preview, eg
    /// if the page is activated or if the settings have changed.
    /// </remarks>
    private async void startVideo() {
        var captureSettings = new MediaCaptureInitializationSettings() {
            StreamingCaptureMode = StreamingCaptureMode.Video
        };
        // Set a NEW MediaCapture! Do not re-use the old one, because the property 
        // change event of the attached property will not fire otherwise.
        this.VideoCapture = new MediaCapture();
        await this.videoCapture.InitializeAsync(captureSettings);
        // Notify the UI about a new video source AFTER the initialisation completed. It 
        // is important to await the initialisation here.
        this.NotifyOfPropertyChange(() => this.VideoCapture);
    }
}