使用 WPF、Caliburn 和 C# 从图像转换为图像源
Posted
技术标签:
【中文标题】使用 WPF、Caliburn 和 C# 从图像转换为图像源【英文标题】:Converting from Image to Imagesource using WPF, Caliburn and C# 【发布时间】:2022-01-18 05:51:48 【问题描述】:我正在尝试在 WPF 中设置网络摄像头流。我有一个项目正在运行,其中所有内容都是代码。但是,我很想让它更干净并将其转换为 MVVM。 我的问题是,我无法将流中的图像绑定到视图,并得到以下错误:
绑定路径 Cameraimage, Taget Image.Source, Target Type ImageSource 不带点
无法从“System.Windows.Controls.Image”类型转换为“System.Windows.Media.ImageSource”。考虑在绑定上设置转换器。
这部分程序的主要处理是 View.xaml ViewModel.cs 和一个实用程序 CameraStreaming.cs -(很明显称为视图和视图模型以外的其他名称,但我试图保持简单)
View.xaml-sn-p
<Border
x:Name="webcamContainer"
Grid.Column="0"
Grid.Row="3"
BorderBrush="Black"
BorderThickness="1">
<Image Source="Binding CameraImage" VerticalAlignment="Top" />
</Border>
ViewModel.cs-sn-p
private Image _cameraImage;
public Image CameraImage
get return _cameraImage;
set _cameraImage = value;
NotifyOfPropertyChange(() => CameraImage);
(....)
var selectedCameraDeviceId = SelectedCamera.OpenCvId;
if (_camera == null || _camera.CameraDeviceId != selectedCameraDeviceId)
_camera?.Dispose();
_camera = new CameraStreaming(
imageControlForRendering: CameraImage, // See my CameraStreaming utility
cameraDeviceId: SelectedCamera.OpenCvId);
try
await _camera.StartCamera(true);
// await _ultraSound.Start(false);
CameraStreaming.cs-sn-p
private readonly Image _imageControlForRendering;
public CameraStreaming(Image imageControlForRendering, int cameraDeviceId)
_imageControlForRendering = imageControlForRendering;
CameraDeviceId = cameraDeviceId;
public async Task StartCamera(bool crop)
if (_previewTask != null && !_previewTask.IsCompleted)
return;
var initializationSemaphore = new SemaphoreSlim(0, 1);
_cancellationTokenSource = new CancellationTokenSource();
_previewTask = Task.Run(async () =>
try
var videoCapture = new VideoCapture();
if (!videoCapture.Open(CameraDeviceId))
throw new ApplicationException("Cannot connect to camera");
using (var frame = new Mat())
while (!_cancellationTokenSource.IsCancellationRequested)
videoCapture.Read(frame);
if (!frame.Empty())
// Releases the lock on first not empty frame
if (initializationSemaphore != null)
initializationSemaphore.Release();
// _lastFrame = BitmapConverter.ToBitmap(frame);
_lastFrame = BitmapConverter.ToBitmap(frame.Flip(FlipMode.Y));
var lastFrameBitmapImage = _lastFrame.ToBitmapSource();
lastFrameBitmapImage.Freeze();
_imageControlForRendering.Dispatcher.Invoke(
() => _imageControlForRendering.Source = lastFrameBitmapImage);
await Task.Delay(10);
videoCapture?.Dispose();
finally
if (initializationSemaphore != null)
initializationSemaphore.Release();
, _cancellationTokenSource.Token);
await initializationSemaphore.WaitAsync();
initializationSemaphore.Dispose();
initializationSemaphore = null;
if (_previewTask.IsFaulted)
// To let the exceptions exit
await _previewTask;
所以.. 我迷路了。由于log4j问题,目前大部分官方文档都被关闭了,我想我看了这么久可能已经失明了:P
【问题讨论】:
看来您可以通过将lastFrameBitmapImage
设置为 ViewModel 的属性并将其与 View 中的图像绑定来解决此问题。
【参考方案1】:
您不能在视图模型中使用System.Windows.Controls.Image
作为图像属性的类型,原因有二。
-
这是一个
UIElement
,因此不属于视图模型
不能分配给视图中另一个图像元素的Source
属性
将类型改为ImageSource
private ImageSource _cameraImage;
public ImageSource CameraImage
get return _cameraImage;
set
_cameraImage = value;
NotifyOfPropertyChange(() => CameraImage);
并使用新的相机框架更新视图模型:
var lastFrameBitmapSource = _lastFrame.ToBitmapSource();
lastFrameBitmapSource.Freeze();
viewModel.CameraImage = lastFrameBitmapSource;
如果您不想将视图模型的引用传递给辅助类,则需要另一种通知机制。
【讨论】:
谢谢!这解决了 Image vs Imagesource 问题!但是,绑定似乎不起作用。相机打开,我可以看到,数据在我的本地人中设置正确。但是,它没有显示。我尝试了 Source="Binding CameraImage" 和 x:Name="CameraImage" (我正在使用 Caliburn),但都不起作用。你知道为什么吗? 您的问题并不清楚,但为了使Source="Binding CameraImage"
工作,您必须将视图模型实例分配给视图的 DataContext 属性,例如主窗口。
我已将其作为一个新问题提出。由于我使用的是 Caliburn,因此数据上下文是自动设置的。但是,我也尝试在后面的代码中设置它,这并没有改变任何东西。 ***.com/questions/70387364/…以上是关于使用 WPF、Caliburn 和 C# 从图像转换为图像源的主要内容,如果未能解决你的问题,请参考以下文章
C# WPF MVVM开发框架Caliburn.Micro 名称Transformer⑩①
C# WPF MVVM开发框架Caliburn.Micro入门介绍①
C# WPF MVVM开发框架Caliburn.Micro自定义引导程序④
C#:Caliburn Micro:如何使用数据绑定控制 WPF 按钮的属性?