如何将 Xamarin.Essentials MediaPicker 与 MVVM 和 DataBinding 一起使用

Posted

技术标签:

【中文标题】如何将 Xamarin.Essentials MediaPicker 与 MVVM 和 DataBinding 一起使用【英文标题】:How do I use Xamarin.Essentials MediaPicker with MVVM and DataBinding 【发布时间】:2021-08-26 06:41:34 【问题描述】:

我正在尝试在我的应用程序中拍摄照片,因为这需要在不同的页面上实现,我需要它在 MVVM 架构中工作。当我在后面的相机页面代码上测试它时,它工作得非常好,但是一旦我实现 DataBinding 和 MVVM,模拟器相机就无法初始化。我没有收到任何构建或部署错误,也不知道从哪里开始寻找。该文档没有太大帮助。每次打开应用程序时都需要保存和重复使用捕获的图像 - 或许要记住这一点。

这是我的 ViewModel:

using System.Collections.Generic;
using System.Text;
using Xamarin.Essentials;
using Xamarin.Forms;
using XamCam.Views;
using MvvmHelpers;
using System.ComponentModel;
using System.Windows.Input;

namespace XamCam.ViewModels

    public class CameraViewModels : BaseViewModel
    
        public CameraViewModels()
        
            TakePhoto = new Command(OnTakePhoto);
        

        public ICommand TakePhoto  get; 

        private Image image; // = new Image();
        public Image CamImage
        
            get => image;
            set
            
                if (image == value)
                    return;
                image = value;
                OnPropertyChanged();
            
        

        async void OnTakePhoto()
        
            var result = await MediaPicker.CapturePhotoAsync();

            if (result != null)
            
                var stream = await result.OpenReadAsync();

                image.Source = ImageSource.FromStream(() => stream);
            
        
    

这是我的视图 XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:viewmodels="clr-namespace:XamCam.ViewModels" 
             x:DataType="viewmodels:CameraViewModels"
             x:Class="XamCam.Views.Camera"
             BackgroundColor="AliceBlue">
    <ContentPage.BindingContext>
        <viewmodels:CameraViewModels/>
    </ContentPage.BindingContext>
    <ContentPage.Content>
        <StackLayout BindingContext="CameraViewModel">
            <Label Text="Welcome to The XamCam!" />
            <Button Text="Take Photo"
                    Command="Binding TakePhoto"/>
            <Image BindingContext="Binding CamImage"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

我怀疑这与我的 CamImage 属性有关,但我对此很陌生,我不确定这是否是绑定媒体对象的正确方法。

【问题讨论】:

MediaPicker 文档中有一个重要提示:“所有方法都必须在 UI 线程上调用,因为权限检查和请求由 Xamarin.Essentials 自动处理。” 为什么会在非 UI 线程 @Jason 上触发命令? 也许我错了 - 但我没有看到它记录了命令总是在主线程上。 @Jason 我接受了这一点,因为我的知识非常初级,我不确定这是否以及如何受到 MVVM 的影响。我的理解是它仍然在主线程上运行,但业务逻辑只是简单地封装在其他地方。不知道我的理解是否正确。 【参考方案1】:

我怀疑这与我的 CamImage 属性有关,但我对此很陌生,我不确定这是否是绑定媒体对象的正确方法。

我建议你可以在 CameraViewModels 中添加ImageSource1 属性,而不是Image 属性。

public class CameraViewModels : INotifyPropertyChanged

    public CameraViewModels()
    
        TakePhoto = new Command(OnTakePhoto);
    

    public ICommand TakePhoto  get; 

    private ImageSource image;
    public ImageSource CamImage
    
        get => image;
        set
        
            if (image == value)
                return;
            image = value;
            RaisePropertyChanged("CamImage");
        
    

    async void OnTakePhoto()
    
        var result = await Xamarin.Essentials.MediaPicker.CapturePhotoAsync();

        if (result != null)
        
            var stream = await result.OpenReadAsync();

            CamImage = ImageSource.FromStream(() => stream);
        
    
    public event PropertyChangedEventHandler PropertyChanged;


    public void RaisePropertyChanged(string propertyName)
    
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        
            handler(this, new PropertyChangedEventArgs(propertyName));
        
    


<ContentPage
x:Class="App1.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1">
<ContentPage.BindingContext>
    <local:CameraViewModels />
</ContentPage.BindingContext>

<StackLayout>
    <StackLayout>
        <Label Text="Welcome to The XamCam!" />
        <Button Command="Binding TakePhoto" Text="Take Photo" />
        <Image Source="Binding CamImage" />
    </StackLayout>
</StackLayout>

【讨论】:

这种方式更有意义,但由于某些奇怪的原因,相机仍然无法启动。我开始怀疑相机是否仅通过点击事件而不是命令启动。不知道为什么。 @JC_vd_Merwe_03 根据您的代码,您通过Button.click启动相机,我将TakePhoto命令绑定到Button.command,我可以打开相机并且没有问题,您试试我的代码吗?还有问题吗? 我试过你的代码,就像我在评论中说的那样,相机仍然没有启动。问题必须在其他地方,因为所有迹象表明它应该起作用。打算尝试一个新项目,看看是否会有所作为。会让你知道的。 @JC_vd_Merwe_03 太奇怪了,因为我使用我的代码,一切正常,我可以成功启动相机。如果您有任何更新,请告诉我。

以上是关于如何将 Xamarin.Essentials MediaPicker 与 MVVM 和 DataBinding 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Xamarin Essentials Share 将应用程序链接共享给其他用户并在他们单击后打开应用程序?

Xamarin Essentials教程安全存储SecureStorage

Xamarin.Forms - 使用 Xamarin.Essentials 在两个坐标之间获取里程

Xamarin Essentials教程发送邮件Email

Xamarin Essentials教程语音播报TextToSpeech

Xamarin Essentials教程剪贴板Clipboard