如何将Xamarin中CameraView捕获逻辑的后置代码转换为MVVM模式
Xamarin 后置代码转MVVM风格实现方案
核心实现逻辑
- 移除所有直接操作控件属性的逻辑,全部迁移到ViewModel层处理
- 将所有需要动态更新的视图属性,封装为ViewModel中支持属性变更通知的可绑定属性
- 通过事件转命令的方式,将CameraView的MediaCaptured事件绑定到ViewModel的处理命令,直接透传事件参数作为入参
步骤1:编写ViewModel代码
using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Input; using Xamarin.CommunityToolkit.ObjectModel; // 按需引入你的项目其他命名空间 public class CameraViewModel : INotifyPropertyChanged { #region 可绑定属性 private CameraCaptureMode _captureMode; public CameraCaptureMode CaptureMode { get => _captureMode; set => SetProperty(ref _captureMode, value); } private bool _isPreviewVideoVisible; public bool IsPreviewVideoVisible { get => _isPreviewVideoVisible; set => SetProperty(ref _isPreviewVideoVisible, value); } private bool _isPreviewPictureVisible; public bool IsPreviewPictureVisible { get => _isPreviewPictureVisible; set => SetProperty(ref _isPreviewPictureVisible, value); } private int _previewPictureRotation; public int PreviewPictureRotation { get => _previewPictureRotation; set => SetProperty(ref _previewPictureRotation, value); } private ImageSource _previewPictureSource; public ImageSource PreviewPictureSource { get => _previewPictureSource; set => SetProperty(ref _previewPictureSource, value); } private MediaSource _previewVideoSource; public MediaSource PreviewVideoSource { get => _previewVideoSource; set => SetProperty(ref _previewVideoSource, value); } private string _doCameraThingsButtonText; public string DoCameraThingsButtonText { get => _doCameraThingsButtonText; set => SetProperty(ref _doCameraThingsButtonText, value); } #endregion public ICommand MediaCapturedCommand { get; } public CameraViewModel() { MediaCapturedCommand = new AsyncCommand<MediaCapturedEventArgs>(OnMediaCaptured); } private Task OnMediaCaptured(MediaCapturedEventArgs e) { switch (CaptureMode) { case CameraCaptureMode.Default: case CameraCaptureMode.Photo: IsPreviewVideoVisible = false; IsPreviewPictureVisible = true; PreviewPictureRotation = e.Rotation; PreviewPictureSource = e.Image; DoCameraThingsButtonText = "Snap Picture"; break; case CameraCaptureMode.Video: IsPreviewPictureVisible = false; IsPreviewVideoVisible = true; PreviewVideoSource = e.Video; DoCameraThingsButtonText = "Start Recording"; break; } return Task.CompletedTask; } #region INotifyPropertyChanged 基础实现 public event PropertyChangedEventHandler PropertyChanged; protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName] string propertyName = "") { if (EqualityComparer<T>.Default.Equals(backingStore, value)) return false; backingStore = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); return true; } #endregion }
如果你使用CommunityToolkit.Mvvm等MVVM工具包,可以通过源生成器大幅简化属性和命令的样板代码。
步骤2:配置XAML绑定
这里提供两种绑定方案可选:
方案A:使用EventToCommand行为(无后置代码)
依赖Xamarin Community Toolkit的行为实现,页面完全没有后置业务代码:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:xct="http://xamarin.com/schemas/2020/toolkit" xmlns:local="clr-namespace:你的项目命名空间" x:Class="你的项目命名空间.CameraPage"> <ContentPage.BindingContext> <local:CameraViewModel /> </ContentPage.BindingContext> <StackLayout> <CameraView x:Name="cameraView" CaptureMode="{Binding CaptureMode}"> <CameraView.Behaviors> <xct:EventToCommandBehavior EventName="MediaCaptured" Command="{Binding MediaCapturedCommand}" EventArgsParameterPath="." /> </CameraView.Behaviors> </CameraView> <Image x:Name="previewPicture" IsVisible="{Binding IsPreviewPictureVisible}" Rotation="{Binding PreviewPictureRotation}" Source="{Binding PreviewPictureSource}" /> <MediaElement x:Name="previewVideo" IsVisible="{Binding IsPreviewVideoVisible}" Source="{Binding PreviewVideoSource}" /> <Button x:Name="doCameraThings" Text="{Binding DoCameraThingsButtonText}" /> </StackLayout> </ContentPage>
方案B:极简后置代码转发(无需引入第三方库)
如果不想引入第三方行为库,也可以在后置代码中仅做参数转发,同样符合MVVM职责分离要求:
页面后置代码:
void CameraView_MediaCaptured(object sender, MediaCapturedEventArgs e) { (BindingContext as CameraViewModel)?.OnMediaCaptured(e); }
XAML中不需要配置行为,其余控件的绑定和方案A完全一致即可。
内容的提问来源于stack exchange,提问作者Reymart Balibad
相关产品推荐
相关产品推荐

