我最近遇到了同样的问题。看来绑定视频源是相当棘手的,因为你需要以正确的顺序初始化、设置和启动预览流。我使用附加属性解决了这个问题:
/// <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);
}
}