From 50bc2a819fe1b90480c7f310472fb8f989fc55c2 Mon Sep 17 00:00:00 2001 From: Shaun Lawrence <17139988+bijington@users.noreply.github.com> Date: Sun, 3 Aug 2025 22:07:59 +0100 Subject: [PATCH 1/4] Initial attempt at platform based processing from the CameraView --- .../CommunityToolkit.Maui.Sample.csproj | 16 ++++++ .../Views/CameraView/BarcodeScanningPage.xaml | 22 ++++++++ .../CameraView/BarcodeScanningPage.xaml.cs | 11 ++++ .../PlatformBarcodeScanningScenario.cs | 26 +++++++++ .../PlatformBarcodeScanningScenario.cs | 53 +++++++++++++++++++ .../PlatformBarcodeScanningScenario.cs | 9 ++++ .../iOS/PlatformBarcodeScanningScenario.cs | 52 ++++++++++++++++++ .../CameraView/BarcodeScanningViewModel.cs | 16 ++++++ .../CameraManager.android.cs | 31 ++++++++++- .../CameraManager.macios.cs | 27 ++++++++++ .../CameraManager.net.cs | 4 ++ .../CameraManager.shared.cs | 28 ++++++++++ .../CommunityToolkit.Maui.Camera.csproj | 6 +++ .../Primitives/CameraScenario.shared.cs | 20 +++++++ .../PlatformCameraScenario.android.cs | 15 ++++++ .../PlatformCameraScenario.macios.cs | 15 ++++++ .../PlatformCameraScenario.shared.cs | 8 +++ .../Views/CameraView.shared.cs | 41 ++++++++++++-- 18 files changed, 395 insertions(+), 5 deletions(-) create mode 100644 samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml create mode 100644 samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs create mode 100644 samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs create mode 100644 samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs create mode 100644 samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs create mode 100644 samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs create mode 100644 samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs create mode 100644 src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs create mode 100644 src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs create mode 100644 src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs create mode 100644 src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.shared.cs diff --git a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj index 0436550172..3042f27b13 100644 --- a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj +++ b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj @@ -89,6 +89,22 @@ + + + Designer + + + + + + BarcodeScanningViewPage.xaml + Code + + + true + + + win-x64 diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml new file mode 100644 index 0000000000..dfc7214ab7 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs new file mode 100644 index 0000000000..08c68d7ad6 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs @@ -0,0 +1,11 @@ +using CommunityToolkit.Maui.Sample.ViewModels.Views; + +namespace CommunityToolkit.Maui.Sample.Pages.Views; + +public partial class BarcodeScanningPage : BasePage +{ + public BarcodeScanningPage(BarcodeScanningViewModel viewModel) : base(viewModel) + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..ce0c2347d1 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,26 @@ +using AndroidX.Camera.Core; + +namespace CommunityToolkit.Maui.Sample; + +public partial class PlatformBarcodeScanningScenario +{ + protected override UseCase CreateUseCase() + { + var imageAnalysis = ImageAnalysis.Builder + // enable the following line if RGBA output is needed. + // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) + .SetTargetResolution(new Size(1280, 720)) + .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest) + .Build(); + // imageAnalysis.SetAnalyzer(executor, ImageAnalysis.Analyzer { + // imageProxy-> + // val rotationDegrees = imageProxy.imageInfo.rotationDegrees + // // insert your code here. + // ... + // // after done, release the ImageProxy object + // imageProxy.close(); + // }); + + return imageAnalysis; + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..6b89842bb7 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,53 @@ +using System.Windows.Input; +using AVFoundation; +using CoreFoundation; + +namespace CommunityToolkit.Maui.Sample; + +/// +/// Apple based implementation +/// +public partial class PlatformBarcodeScanningScenario +{ + protected override AVCaptureOutput CreateOutput() + { + var output = new AVCaptureMetadataOutput(); + + output.SetDelegate(new BarcodeDetectionDelegate(Command), DispatchQueue.MainQueue); + output.MetadataObjectTypes = + AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code; + + return output; + } +} + +sealed class BarcodeDetectionDelegate : AVCaptureMetadataOutputObjectsDelegate +{ + readonly ICommand command; + + public BarcodeDetectionDelegate(ICommand command) + { + this.command = command; + } + + public override void DidOutputMetadataObjects( + AVCaptureMetadataOutput captureOutput, + AVMetadataObject[] metadataObjects, + AVCaptureConnection connection) + { + foreach (var metadataObject in metadataObjects) + { + if (metadataObject is AVMetadataMachineReadableCodeObject readableObject) + { + var code = readableObject.StringValue; + + Console.WriteLine($"Metadata object {code} at {string.Join(",", readableObject.Corners?? [])}"); + + if (this.command.CanExecute(readableObject.StringValue)) + { + this.command.Execute(readableObject.StringValue); + } + } + } + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..6864a50678 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,9 @@ +using System.Windows.Input; +using CommunityToolkit.Maui.Core; + +namespace CommunityToolkit.Maui.Sample; + +public partial class PlatformBarcodeScanningScenario : PlatformCameraScenario +{ + public ICommand Command { get; set; } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..1084f7d053 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,52 @@ +using AVFoundation; +using CoreFoundation; + +namespace CommunityToolkit.Maui.Sample; + +/// +/// Apple based implementation +/// +public partial class PlatformBarcodeScanningScenario +{ + protected override AVCaptureOutput CreateOutput() + { + var output = new AVCaptureMetadataOutput(); + + output.SetDelegate(new BarcodeDetectionDelegate(Command), DispatchQueue.MainQueue); + output.MetadataObjectTypes = + AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code; + + return output; + } +} + +sealed class BarcodeDetectionDelegate : AVCaptureMetadataOutputObjectsDelegate +{ + readonly ICommand command; + + public BarcodeDetectionDelegate(ICommand command) + { + this.command = command; + } + + public override void DidOutputMetadataObjects( + AVCaptureMetadataOutput captureOutput, + AVMetadataObject[] metadataObjects, + AVCaptureConnection connection) + { + foreach (var metadataObject in metadataObjects) + { + if (metadataObject is AVMetadataMachineReadableCodeObject readableObject) + { + var code = readableObject.StringValue; + + Console.WriteLine($"Metadata object {code} at {string.Join(",", readableObject.Corners?? [])}"); + + if (this.command.CanExecute(readableObject.StringValue)) + { + this.command.Execute(readableObject.StringValue); + } + } + } + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs new file mode 100644 index 0000000000..25dcffcb33 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs @@ -0,0 +1,16 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +namespace CommunityToolkit.Maui.Sample.ViewModels.Views; + +public partial class BarcodeScanningViewModel() : BaseViewModel +{ + [ObservableProperty] + public partial string DetectedCode { get; set; } + + [RelayCommand] + void OnCodeDetected(string code) + { + DetectedCode = code; + } +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs index c642ca4218..cd2fd590e6 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs @@ -19,6 +19,8 @@ namespace CommunityToolkit.Maui.Core; partial class CameraManager { readonly Context context = mauiContext.Context ?? throw new CameraException($"Unable to retrieve {nameof(Context)}"); + + readonly IList additionalUseCases = []; NativePlatformCameraPreviewView? previewView; IExecutorService? cameraExecutor; @@ -220,7 +222,14 @@ protected virtual async partial Task PlatformStartCameraPreview(CancellationToke var cameraSelector = cameraView.SelectedCamera.CameraSelector ?? throw new CameraException($"Unable to retrieve {nameof(CameraSelector)}"); var owner = (ILifecycleOwner)context; - camera = processCameraProvider.BindToLifecycle(owner, cameraSelector, cameraPreview, imageCapture); + camera = processCameraProvider.BindToLifecycle( + owner, + cameraSelector, + [ + .. additionalUseCases, + cameraPreview, + imageCapture + ]); cameraControl = camera.CameraControl; @@ -257,6 +266,26 @@ protected virtual partial ValueTask PlatformTakePicture(CancellationToken token) imageCapture?.TakePicture(cameraExecutor, imageCallback); return ValueTask.CompletedTask; } + + internal virtual partial void AddPlatformScenario(PlatformCameraScenario scenario) + { + AddUseCase(scenario.UseCase); + } + + internal virtual partial void RemovePlatformScenario(PlatformCameraScenario scenario) + { + RemoveUseCase(scenario.UseCase); + } + + internal void AddUseCase(UseCase useCase) + { + additionalUseCases.Add(useCase); + } + + internal void RemoveUseCase(UseCase useCase) + { + additionalUseCases.Remove(useCase); + } void SetImageCaptureTargetRotation(int rotation) { diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs index 17941d0cf7..0c3b3c234c 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs @@ -11,6 +11,8 @@ partial class CameraManager { // TODO: Check if we really need this readonly NSDictionary codecSettings = new([AVVideo.CodecKey], [new NSString("jpeg")]); + + readonly IList additionalCaptureOutputs = []; AVCaptureSession? captureSession; AVCapturePhotoOutput? photoOutput; @@ -157,6 +159,11 @@ protected virtual async partial Task PlatformStartCameraPreview(CancellationToke captureDevice = cameraView.SelectedCamera.CaptureDevice ?? throw new CameraException($"No Camera found"); captureInput = new AVCaptureDeviceInput(captureDevice, out _); captureSession.AddInput(captureInput); + + foreach (var output in additionalCaptureOutputs) + { + captureSession.AddOutput(output); + } if (photoOutput is null) { @@ -265,6 +272,26 @@ protected virtual void Dispose(bool disposing) } } + internal virtual partial void AddPlatformScenario(PlatformCameraScenario scenario) + { + AddOutput(scenario.Output); + } + + internal virtual partial void RemovePlatformScenario(PlatformCameraScenario scenario) + { + RemoveOutput(scenario.Output); + } + + internal void AddOutput(AVCaptureOutput captureOutput) + { + additionalCaptureOutputs.Add(captureOutput); + } + + internal void RemoveOutput(AVCaptureOutput captureOutput) + { + additionalCaptureOutputs.Remove(captureOutput); + } + static AVCaptureVideoOrientation GetVideoOrientation() { IEnumerable scenes = UIApplication.SharedApplication.ConnectedScenes; diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.net.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.net.cs index 41dae1d618..69eef9b7d8 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.net.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.net.cs @@ -23,4 +23,8 @@ partial class CameraManager protected virtual partial void PlatformDisconnect() => throw new NotSupportedException(notSupportedMessage); protected virtual partial ValueTask PlatformTakePicture(CancellationToken token) => throw new NotSupportedException(notSupportedMessage); + + internal virtual partial void AddPlatformScenario(PlatformCameraScenario scenario) => throw new NotSupportedException(notSupportedMessage); + + internal virtual partial void RemovePlatformScenario(PlatformCameraScenario scenario) => throw new NotSupportedException(notSupportedMessage); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs index d7703d2572..307d048572 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs @@ -18,6 +18,10 @@ partial class CameraManager( ICameraProvider cameraProvider, Action onLoaded) : IDisposable { + readonly IList scenarios = []; + + protected IReadOnlyList Scenarios => scenarios.AsReadOnly(); + internal Action OnLoaded { get; } = onLoaded; internal bool IsInitialized { get; private set; } @@ -131,4 +135,28 @@ public async ValueTask UpdateCurrentCamera(CameraInfo? cameraInfo, CancellationT /// Stops the preview from the camera, at the platform-specific level. /// protected virtual partial void PlatformStopCameraPreview(); + + internal void AddScenario(CameraScenario scenario) + { + this.scenarios.Add(scenario); + + if (scenario is PlatformCameraScenario platformScenario) + { + AddPlatformScenario(platformScenario); + } + } + + internal void RemoveScenario(CameraScenario scenario) + { + this.scenarios.Remove(scenario); + + if (scenario is PlatformCameraScenario platformScenario) + { + RemovePlatformScenario(platformScenario); + } + } + + internal virtual partial void AddPlatformScenario(PlatformCameraScenario scenario); + + internal virtual partial void RemovePlatformScenario(PlatformCameraScenario scenario); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/CommunityToolkit.Maui.Camera.csproj b/src/CommunityToolkit.Maui.Camera/CommunityToolkit.Maui.Camera.csproj index bd22368e3c..228838d231 100644 --- a/src/CommunityToolkit.Maui.Camera/CommunityToolkit.Maui.Camera.csproj +++ b/src/CommunityToolkit.Maui.Camera/CommunityToolkit.Maui.Camera.csproj @@ -69,4 +69,10 @@ + + + ..\..\..\..\..\..\..\..\..\..\..\usr\local\share\dotnet\packs\Microsoft.MacCatalyst.Ref.net9.0_18.5\18.5.9199\ref\net9.0\Microsoft.MacCatalyst.dll + + + diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs b/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs new file mode 100644 index 0000000000..45458d4217 --- /dev/null +++ b/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs @@ -0,0 +1,20 @@ +namespace CommunityToolkit.Maui.Core; + +/// +/// Base class for output based processing for camera related activities. +/// +public abstract class CameraScenario +{ + /// + /// Gets whether the scenario has been initialized. + /// + public bool IsInitialized { get; protected set; } + + /// + /// Initializes the scenario. + /// + public virtual void Initialize() + { + IsInitialized = true; + } +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs new file mode 100644 index 0000000000..eee1c80030 --- /dev/null +++ b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs @@ -0,0 +1,15 @@ +using AndroidX.Camera.Core; + +namespace CommunityToolkit.Maui.Core; + +/// +/// +/// +partial class PlatformCameraScenario : CameraScenario +{ + /// + /// + /// + /// + protected abstract UseCase CreateUseCase(); +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs new file mode 100644 index 0000000000..74774beca8 --- /dev/null +++ b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs @@ -0,0 +1,15 @@ +using AVFoundation; + +namespace CommunityToolkit.Maui.Core; + +/// +/// +/// +partial class PlatformCameraScenario : CameraScenario +{ + /// + /// + /// + /// + protected abstract AVCaptureOutput CreateOutput(); +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.shared.cs b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.shared.cs new file mode 100644 index 0000000000..987b58dd33 --- /dev/null +++ b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.shared.cs @@ -0,0 +1,8 @@ +namespace CommunityToolkit.Maui.Core; + +/// +/// +/// +public abstract partial class PlatformCameraScenario : CameraScenario +{ +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs index edbd26460d..0404487f92 100644 --- a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.ObjectModel; +using System.ComponentModel; using System.Runtime.Versioning; using System.Windows.Input; using CommunityToolkit.Maui.Core; @@ -18,6 +19,24 @@ public partial class CameraView : View, ICameraView, IDisposable static readonly BindablePropertyKey isAvailablePropertyKey = BindableProperty.CreateReadOnly(nameof(IsAvailable), typeof(bool), typeof(CameraView), CameraViewDefaults.IsAvailable); + internal static readonly BindablePropertyKey CameraScenarioPropertyKey = BindableProperty.CreateReadOnly(nameof(Scenarios), typeof(IList), typeof(CameraView), default(IList), + defaultValueCreator: bindable => + { + var collection = new ObservableCollection(); + return collection; + }); + + /// Bindable property for . + public static readonly BindableProperty CameraScenarioProperty = CameraScenarioPropertyKey.BindableProperty; + + /// + /// + /// + public IList Scenarios + { + get { return (IList)GetValue(BehaviorsProperty); } + } + /// /// Backing for the property. /// @@ -251,12 +270,26 @@ public async Task CaptureImage(CancellationToken token) } /// - public Task StartCameraPreview(CancellationToken token) => - Handler.CameraManager.StartCameraPreview(token); + public Task StartCameraPreview(CancellationToken token) + { + foreach (var scenario in Scenarios) + { + Handler.CameraManager.AddScenario(scenario); + } + + return Handler.CameraManager.StartCameraPreview(token); + } /// - public void StopCameraPreview() => + public void StopCameraPreview() + { + foreach (var scenario in Scenarios) + { + Handler.CameraManager.RemoveScenario(scenario); + } + Handler.CameraManager.StopCameraPreview(); + } /// protected virtual void Dispose(bool disposing) From f51e909207868c43df725b77aeebfd8e980a91e5 Mon Sep 17 00:00:00 2001 From: Shaun Lawrence <17139988+bijington@users.noreply.github.com> Date: Sun, 3 Aug 2025 22:09:06 +0100 Subject: [PATCH 2/4] Remove auto gen project code --- .../CommunityToolkit.Maui.Sample.csproj | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj index 3042f27b13..0436550172 100644 --- a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj +++ b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj @@ -89,22 +89,6 @@ - - - Designer - - - - - - BarcodeScanningViewPage.xaml - Code - - - true - - - win-x64 From 504a92fa32e429d62b53bd5dd4f226323b7cdd21 Mon Sep 17 00:00:00 2001 From: Shaun Lawrence <17139988+bijington@users.noreply.github.com> Date: Sun, 3 Aug 2025 22:18:40 +0100 Subject: [PATCH 3/4] More bits --- .../CommunityToolkit.Maui.Sample.csproj | 6 +++ .../PlatformBarcodeScanningScenario.cs | 39 +++++++++++-------- .../PlatformBarcodeScanningScenario.cs | 29 ++++++++------ .../PlatformBarcodeScanningScenario.cs | 5 ++- .../iOS/PlatformBarcodeScanningScenario.cs | 30 ++++++++------ .../CommunityToolkit.Maui.Camera.csproj | 6 --- .../PlatformCameraScenario.android.cs | 2 +- .../PlatformCameraScenario.macios.cs | 3 +- 8 files changed, 72 insertions(+), 48 deletions(-) diff --git a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj index 0436550172..dfe87626c4 100644 --- a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj +++ b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj @@ -89,6 +89,12 @@ + + + true + + + win-x64 diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs index ce0c2347d1..91dcbc876c 100644 --- a/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs @@ -4,23 +4,30 @@ namespace CommunityToolkit.Maui.Sample; public partial class PlatformBarcodeScanningScenario { - protected override UseCase CreateUseCase() + readonly Lazy lazyUseCase; + + public PlatformBarcodeScanningScenario() { - var imageAnalysis = ImageAnalysis.Builder - // enable the following line if RGBA output is needed. - // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) - .SetTargetResolution(new Size(1280, 720)) - .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest) - .Build(); - // imageAnalysis.SetAnalyzer(executor, ImageAnalysis.Analyzer { - // imageProxy-> - // val rotationDegrees = imageProxy.imageInfo.rotationDegrees - // // insert your code here. - // ... - // // after done, release the ImageProxy object - // imageProxy.close(); - // }); + lazyUseCase = new Lazy(() => + { + var imageAnalysis = ImageAnalysis.Builder + // enable the following line if RGBA output is needed. + // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) + .SetTargetResolution(new Size(1280, 720)) + .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest) + .Build(); + // imageAnalysis.SetAnalyzer(executor, ImageAnalysis.Analyzer { + // imageProxy-> + // val rotationDegrees = imageProxy.imageInfo.rotationDegrees + // // insert your code here. + // ... + // // after done, release the ImageProxy object + // imageProxy.close(); + // }); - return imageAnalysis; + return imageAnalysis; + }); } + + public override UseCase UseCase => lazyUseCase.Value; } \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs index 6b89842bb7..9a20a29ae0 100644 --- a/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/MacCatalyst/PlatformBarcodeScanningScenario.cs @@ -9,23 +9,30 @@ namespace CommunityToolkit.Maui.Sample; /// public partial class PlatformBarcodeScanningScenario { - protected override AVCaptureOutput CreateOutput() + readonly Lazy lazyOutput; + + public PlatformBarcodeScanningScenario() { - var output = new AVCaptureMetadataOutput(); - - output.SetDelegate(new BarcodeDetectionDelegate(Command), DispatchQueue.MainQueue); - output.MetadataObjectTypes = - AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code; - - return output; + lazyOutput = new Lazy(() => + { + var output = new AVCaptureMetadataOutput(); + + output.SetDelegate(new BarcodeDetectionDelegate(Command), DispatchQueue.MainQueue); + output.MetadataObjectTypes = + AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code; + + return output; + }); } + + public override AVCaptureOutput Output => lazyOutput.Value; } sealed class BarcodeDetectionDelegate : AVCaptureMetadataOutputObjectsDelegate { - readonly ICommand command; + readonly ICommand? command; - public BarcodeDetectionDelegate(ICommand command) + public BarcodeDetectionDelegate(ICommand? command) { this.command = command; } @@ -43,7 +50,7 @@ public override void DidOutputMetadataObjects( Console.WriteLine($"Metadata object {code} at {string.Join(",", readableObject.Corners?? [])}"); - if (this.command.CanExecute(readableObject.StringValue)) + if (this.command?.CanExecute(readableObject.StringValue) is true) { this.command.Execute(readableObject.StringValue); } diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs index 6864a50678..05562ea582 100644 --- a/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/PlatformBarcodeScanningScenario.cs @@ -3,7 +3,10 @@ namespace CommunityToolkit.Maui.Sample; +/// +/// +/// public partial class PlatformBarcodeScanningScenario : PlatformCameraScenario { - public ICommand Command { get; set; } + public ICommand? Command { get; set; } } \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs index 1084f7d053..9a20a29ae0 100644 --- a/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/iOS/PlatformBarcodeScanningScenario.cs @@ -1,3 +1,4 @@ +using System.Windows.Input; using AVFoundation; using CoreFoundation; @@ -8,23 +9,30 @@ namespace CommunityToolkit.Maui.Sample; /// public partial class PlatformBarcodeScanningScenario { - protected override AVCaptureOutput CreateOutput() + readonly Lazy lazyOutput; + + public PlatformBarcodeScanningScenario() { - var output = new AVCaptureMetadataOutput(); - - output.SetDelegate(new BarcodeDetectionDelegate(Command), DispatchQueue.MainQueue); - output.MetadataObjectTypes = - AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code; - - return output; + lazyOutput = new Lazy(() => + { + var output = new AVCaptureMetadataOutput(); + + output.SetDelegate(new BarcodeDetectionDelegate(Command), DispatchQueue.MainQueue); + output.MetadataObjectTypes = + AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code; + + return output; + }); } + + public override AVCaptureOutput Output => lazyOutput.Value; } sealed class BarcodeDetectionDelegate : AVCaptureMetadataOutputObjectsDelegate { - readonly ICommand command; + readonly ICommand? command; - public BarcodeDetectionDelegate(ICommand command) + public BarcodeDetectionDelegate(ICommand? command) { this.command = command; } @@ -42,7 +50,7 @@ public override void DidOutputMetadataObjects( Console.WriteLine($"Metadata object {code} at {string.Join(",", readableObject.Corners?? [])}"); - if (this.command.CanExecute(readableObject.StringValue)) + if (this.command?.CanExecute(readableObject.StringValue) is true) { this.command.Execute(readableObject.StringValue); } diff --git a/src/CommunityToolkit.Maui.Camera/CommunityToolkit.Maui.Camera.csproj b/src/CommunityToolkit.Maui.Camera/CommunityToolkit.Maui.Camera.csproj index 228838d231..bd22368e3c 100644 --- a/src/CommunityToolkit.Maui.Camera/CommunityToolkit.Maui.Camera.csproj +++ b/src/CommunityToolkit.Maui.Camera/CommunityToolkit.Maui.Camera.csproj @@ -69,10 +69,4 @@ - - - ..\..\..\..\..\..\..\..\..\..\..\usr\local\share\dotnet\packs\Microsoft.MacCatalyst.Ref.net9.0_18.5\18.5.9199\ref\net9.0\Microsoft.MacCatalyst.dll - - - diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs index eee1c80030..18ff8675a9 100644 --- a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs +++ b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.android.cs @@ -11,5 +11,5 @@ partial class PlatformCameraScenario : CameraScenario /// /// /// - protected abstract UseCase CreateUseCase(); + public abstract UseCase UseCase { get; } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs index 74774beca8..6d703c0ec3 100644 --- a/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs +++ b/src/CommunityToolkit.Maui.Camera/Primitives/PlatformCameraScenario.macios.cs @@ -10,6 +10,5 @@ partial class PlatformCameraScenario : CameraScenario /// /// /// - /// - protected abstract AVCaptureOutput CreateOutput(); + public abstract AVCaptureOutput Output { get; } } \ No newline at end of file From dd2e5e8cfd575375fa1a5329abd047fe11bc8b27 Mon Sep 17 00:00:00 2001 From: Shaun Lawrence <17139988+bijington@users.noreply.github.com> Date: Tue, 5 Aug 2025 20:19:16 +0100 Subject: [PATCH 4/4] Playing around with Android possible scanning --- .../AppShell.xaml.cs | 1 + .../CommunityToolkit.Maui.Sample.csproj | 7 +- .../MauiProgram.cs | 1 + .../CameraView/BarcodeScanningPage.xaml.cs | 8 ++ .../PlatformBarcodeScanningScenario.cs | 25 +++++ .../Platforms/Android/BarcodeAnalyzer.cs | 93 +++++++++++++++++++ .../PlatformBarcodeScanningScenario.cs | 29 +++--- .../CameraView/BarcodeScanningViewModel.cs | 10 +- .../ViewModels/Views/ViewsGalleryViewModel.cs | 1 + .../Primitives/CameraScenario.shared.cs | 2 +- .../Views/CameraView.shared.cs | 6 +- 11 files changed, 157 insertions(+), 26 deletions(-) create mode 100644 samples/CommunityToolkit.Maui.Sample/PlatformBarcodeScanningScenario.cs create mode 100644 samples/CommunityToolkit.Maui.Sample/Platforms/Android/BarcodeAnalyzer.cs diff --git a/samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs b/samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs index 12721c1b46..9c5d1ef42a 100644 --- a/samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs +++ b/samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs @@ -118,6 +118,7 @@ public partial class AppShell : Shell CreateViewModelMapping(), CreateViewModelMapping(), CreateViewModelMapping(), + CreateViewModelMapping(), CreateViewModelMapping(), CreateViewModelMapping(), CreateViewModelMapping(), diff --git a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj index dfe87626c4..9c4272a54f 100644 --- a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj +++ b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj @@ -89,10 +89,9 @@ - - - true - + + + diff --git a/samples/CommunityToolkit.Maui.Sample/MauiProgram.cs b/samples/CommunityToolkit.Maui.Sample/MauiProgram.cs index 1dd763355a..41bdde8417 100644 --- a/samples/CommunityToolkit.Maui.Sample/MauiProgram.cs +++ b/samples/CommunityToolkit.Maui.Sample/MauiProgram.cs @@ -247,6 +247,7 @@ static void RegisterViewsAndViewModels(in IServiceCollection services) services.AddTransientWithShellRoute(); // Add Views Pages + ViewModels + services.AddTransientWithShellRoute(); services.AddTransientWithShellRoute(); services.AddTransientWithShellRoute(); services.AddTransientWithShellRoute(); diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs index 08c68d7ad6..362db8961e 100644 --- a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/BarcodeScanningPage.xaml.cs @@ -8,4 +8,12 @@ public BarcodeScanningPage(BarcodeScanningViewModel viewModel) : base(viewModel) { InitializeComponent(); } + + protected override async void OnAppearing() + { + base.OnAppearing(); + + var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3)); + await BindingContext.RefreshCamerasCommand.ExecuteAsync(cancellationTokenSource.Token); + } } \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/PlatformBarcodeScanningScenario.cs new file mode 100644 index 0000000000..d896c41faf --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/PlatformBarcodeScanningScenario.cs @@ -0,0 +1,25 @@ +using System.Windows.Input; +using CommunityToolkit.Maui.Core; + +namespace CommunityToolkit.Maui.Sample; + +/// +/// +/// +public partial class PlatformBarcodeScanningScenario : PlatformCameraScenario +{ + /// + /// Backing BindableProperty for the property. + /// + public static readonly BindableProperty CommandProperty = + BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(PlatformBarcodeScanningScenario)); + + /// + /// The Command that should be executed when a barcode is detected. + /// + public ICommand? Command + { + get => (ICommand?)GetValue(CommandProperty); + set => SetValue(CommandProperty, value); + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/Android/BarcodeAnalyzer.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/BarcodeAnalyzer.cs new file mode 100644 index 0000000000..a35c4a3b11 --- /dev/null +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/BarcodeAnalyzer.cs @@ -0,0 +1,93 @@ +using System.Diagnostics; +using System.Windows.Input; +using Android.Gms.Tasks; +using Android.Runtime; +using AndroidX.Camera.Core; +using Xamarin.Google.MLKit.Vision.Barcode.Common; +using Xamarin.Google.MLKit.Vision.BarCode; +using Xamarin.Google.MLKit.Vision.Common; + +using Scanner = Xamarin.Google.MLKit.Vision.BarCode.BarcodeScanning; + +namespace CommunityToolkit.Maui.Sample; + +public class BarcodeAnalyzer : Java.Lang.Object, ImageAnalysis.IAnalyzer +{ + readonly ICommand command; + IBarcodeScanner? barcodeScanner; + readonly Lock resultsLock = new(); + + public BarcodeAnalyzer(ICommand command) + { + this.command = command; + } + + internal void UpdateSymbologies() + { + barcodeScanner?.Dispose(); + barcodeScanner = Scanner.GetClient(new BarcodeScannerOptions.Builder() + .SetBarcodeFormats(Barcode.FormatAllFormats) + .Build()); + } + + public void Analyze(IImageProxy proxy) + { + try + { + ArgumentNullException.ThrowIfNull(proxy?.Image); + ArgumentNullException.ThrowIfNull(barcodeScanner); + + using var inputImage = InputImage.FromMediaImage(proxy.Image, 0); + using var task = barcodeScanner.Process(inputImage); + var result = TasksClass.Await(task); + + lock (resultsLock) + { + ProcessResults(result); + } + + result?.Dispose(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + finally + { + try + { + proxy?.Close(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + } + + void ProcessResults(Java.Lang.Object? result) + { + if (result is not JavaList javaList) + { + return; + } + + foreach (Barcode barcode in javaList) + { + if (barcode is null) + { + continue; + } + + if (string.IsNullOrEmpty(barcode.DisplayValue) && string.IsNullOrEmpty(barcode.RawValue)) + { + continue; + } + + if (this.command?.CanExecute(barcode.RawValue) is true) + { + this.command.Execute(barcode.RawValue); + } + } + } +} \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs index 91dcbc876c..107a690351 100644 --- a/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs +++ b/samples/CommunityToolkit.Maui.Sample/Platforms/Android/PlatformBarcodeScanningScenario.cs @@ -4,30 +4,27 @@ namespace CommunityToolkit.Maui.Sample; public partial class PlatformBarcodeScanningScenario { - readonly Lazy lazyUseCase; + readonly Lazy? lazyUseCase = null; public PlatformBarcodeScanningScenario() { lazyUseCase = new Lazy(() => { - var imageAnalysis = ImageAnalysis.Builder - // enable the following line if RGBA output is needed. - // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) - .SetTargetResolution(new Size(1280, 720)) - .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest) - .Build(); - // imageAnalysis.SetAnalyzer(executor, ImageAnalysis.Analyzer { - // imageProxy-> - // val rotationDegrees = imageProxy.imageInfo.rotationDegrees - // // insert your code here. - // ... - // // after done, release the ImageProxy object - // imageProxy.close(); - // }); + var imageAnalysis = + new ImageAnalysis.Builder() + .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest) + .Build(); + + if (imageAnalysis.BackgroundExecutor is null) + { + throw new InvalidOperationException("Background executor must be set before use case."); + } + + imageAnalysis.SetAnalyzer(imageAnalysis.BackgroundExecutor, new BarcodeAnalyzer(Command!)); return imageAnalysis; }); } - public override UseCase UseCase => lazyUseCase.Value; + public override UseCase UseCase => lazyUseCase?.Value!; } \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs index 25dcffcb33..3a9da2db49 100644 --- a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs +++ b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/BarcodeScanningViewModel.cs @@ -1,10 +1,13 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Maui.Core; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace CommunityToolkit.Maui.Sample.ViewModels.Views; -public partial class BarcodeScanningViewModel() : BaseViewModel +public partial class BarcodeScanningViewModel(ICameraProvider cameraProvider) : BaseViewModel { + readonly ICameraProvider cameraProvider = cameraProvider; + [ObservableProperty] public partial string DetectedCode { get; set; } @@ -13,4 +16,7 @@ void OnCodeDetected(string code) { DetectedCode = code; } + + [RelayCommand] + async Task RefreshCameras(CancellationToken token) => await cameraProvider.RefreshAvailableCameras(token); } \ No newline at end of file diff --git a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGalleryViewModel.cs b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGalleryViewModel.cs index ea038112a0..f3c8267d29 100644 --- a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGalleryViewModel.cs +++ b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGalleryViewModel.cs @@ -15,6 +15,7 @@ public sealed partial class ViewsGalleryViewModel() : BaseGalleryViewModel( SectionModel.Create("AvatarView Shadows Page", Colors.Red, "A page demonstrating AvatarViews with various shadow options."), SectionModel.Create("AvatarView Shapes Page", Colors.Red, "A page demonstrating AvatarViews with various shape options."), SectionModel.Create("AvatarView Sizes Page", Colors.Red, "A page demonstrating AvatarViews with various size options."), + SectionModel.Create("Barcode Page", Colors.Red, "Barcode scanning support using the CameraView."), SectionModel.Create("CameraView Page", Colors.Red, "CameraView is a view for displaying camera output."), SectionModel.Create("DrawingView", Colors.Red, "DrawingView provides a canvas for users to \"paint\" on the screen. The drawing can also be captured and displayed as an Image."), SectionModel.Create("Expander Page", Colors.Red, "Expander allows collapse and expand content."), diff --git a/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs b/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs index 45458d4217..6652592f94 100644 --- a/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/Primitives/CameraScenario.shared.cs @@ -3,7 +3,7 @@ namespace CommunityToolkit.Maui.Core; /// /// Base class for output based processing for camera related activities. /// -public abstract class CameraScenario +public abstract class CameraScenario : BindableObject { /// /// Gets whether the scenario has been initialized. diff --git a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs index 0404487f92..c97aa48a23 100644 --- a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs @@ -19,7 +19,7 @@ public partial class CameraView : View, ICameraView, IDisposable static readonly BindablePropertyKey isAvailablePropertyKey = BindableProperty.CreateReadOnly(nameof(IsAvailable), typeof(bool), typeof(CameraView), CameraViewDefaults.IsAvailable); - internal static readonly BindablePropertyKey CameraScenarioPropertyKey = BindableProperty.CreateReadOnly(nameof(Scenarios), typeof(IList), typeof(CameraView), default(IList), + internal static readonly BindablePropertyKey ScenariosPropertyKey = BindableProperty.CreateReadOnly(nameof(Scenarios), typeof(IList), typeof(CameraView), default(IList), defaultValueCreator: bindable => { var collection = new ObservableCollection(); @@ -27,14 +27,14 @@ public partial class CameraView : View, ICameraView, IDisposable }); /// Bindable property for . - public static readonly BindableProperty CameraScenarioProperty = CameraScenarioPropertyKey.BindableProperty; + public static readonly BindableProperty ScenariosProperty = ScenariosPropertyKey.BindableProperty; /// /// /// public IList Scenarios { - get { return (IList)GetValue(BehaviorsProperty); } + get { return (IList)GetValue(ScenariosProperty); } } ///