繁体   English   中英

如何在Xamarin.Forms中设置图像控件的双向绑定?

[英]How to set two way binding for Image control in Xamarin.Forms?

我有一个带有图像的自定义视图MyPhotoView 我已加载图片。 现在,我想在继续按钮单击时更改图像。 我尝试使用TwoWay Binding和Binding属性的设置值,但是单击“ Continue按钮时图像不会更改。

上一页按钮单击//从上一页的ViewModel调用(从图库中获取图像)

List<Image> currentOriginalImages = new List<Image>();
foreach (var item in _pictureSources)
{
    currentOriginalImages.Add(new Image() { Source = item });
}
var viewModel = new CropPhotoViewModel(currentOriginalImages);

XAML中使用的自定义控件MyPhotoView

public class MyPhotoView : View
{
    public static readonly BindableProperty CropTopLeftXProperty =
        BindableProperty.Create(nameof(CropTopLeftX), typeof (float), typeof (MyPhotoView), 0f, BindingMode.TwoWay);

    public static readonly BindableProperty CropTopLeftYProperty =
        BindableProperty.Create(nameof(CropTopLeftY), typeof (float), typeof (MyPhotoView), 0f, BindingMode.TwoWay);

    public static readonly BindableProperty CropWidthProperty =
        BindableProperty.Create(nameof(CropWidth), typeof (float), typeof (MyPhotoView), 0f, BindingMode.TwoWay);

    public static readonly BindableProperty CropHeightProperty =
        BindableProperty.Create(nameof(CropHeight), typeof (float), typeof (MyPhotoView), 0f, BindingMode.TwoWay);

    public static readonly BindableProperty OriginalImageProperty =
        BindableProperty.Create(nameof(OriginalImage), typeof (Image), typeof (MyPhotoView),null,BindingMode.TwoWay);

    public float CropTopLeftX
    {
        get { return (float) GetValue(CropTopLeftXProperty); }
        set { SetValue(CropTopLeftXProperty, value); }
    }

    public float CropTopLeftY
    {
        get { return (float) GetValue(CropTopLeftYProperty); }
        set { SetValue(CropTopLeftYProperty, value); }
    }

    public float CropWidth
    {
        get { return (float) GetValue(CropWidthProperty); }
        set { SetValue(CropWidthProperty, value); }
    }

    public float CropHeight
    {
        get { return (float) GetValue(CropHeightProperty); }
        set { SetValue(CropHeightProperty, value); }
    }

    public Image OriginalImage
    {
        get { return (Image) GetValue(OriginalImageProperty); }
        set { SetValue(OriginalImageProperty, value); }
    }
}

XAML:

<?xml version="1.0" encoding="UTF-8"?>
<local:ContentPageWithCustomBackButton
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MyProject;assembly=MyProject"
    x:Class="MyProject.CropPhotoPage"
    Title="Upload Photo">
    <ContentPage.ToolbarItems>
        <ToolbarItem Icon="icon-nav-back" Order="Primary" Priority="0" Command="{Binding GoBackCommand}" />
    </ContentPage.ToolbarItems>
    <ContentPage.Content>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="auto" />
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="auto" />
            </Grid.ColumnDefinitions>

            <local:MyPhotoView Grid.Row="0" Grid.ColumnSpan="3"
                                 x:Name="MyPhotoView"
                                 OriginalImage="{Binding OriginalImage}"
                                 CropTopLeftX="{Binding CropTopLeftX}"
                                 CropTopLeftY="{Binding CropTopLeftY}"
                                 CropWidth="{Binding CropWidth}"
                                 CropHeight="{Binding CropHeight}" />

            <Button Grid.Row="1" Grid.Column="0" Margin="20,0,0,19"
                    Text="Cancel" Clicked="CancelClicked" />

            <Button Grid.Row="1" Grid.Column="2" Margin="0,0,20,19" Clicked="ContinueClicked"
                      Text="Continue" Command="{Binding ContinueCommand}" />

        </Grid>
    </ContentPage.Content>
</local:ContentPageWithCustomBackButton>

CS页面

public partial class CropPhotoPage : ContentPageWithCustomBackButton
{
    public CropPhotoPage()
    {
        InitializeComponent();
        BindingContext = App.Locator.CropPhoto;
    }

    public CropPhotoPage(CropPhotoViewModel bindingContext)
    {
        InitializeComponent();
        BindingContext =  bindingContext;
    }

    private void CancelClicked(object sender, EventArgs e)
    {
        MyPhotoView.ResetCrop();
    }

    private void ContinueClicked(object sender, EventArgs e)
    {
        MyPhotoView.ApplyCrop();
    }
}

视图模型

public CropPhotoViewModel(List<Image> images)
{
    ContinueCommand = new RelayCommand(async () => await ContinueCommandExecute());
    _images = images;
    OriginalImage = images[0];  
}
public Image OriginalImage { get; set; }
public List<Image> _images { get; set; }
public float CropTopLeftX { get; set; }
public float CropTopLeftY { get; set; }
public float CropWidth { get; set; }
public float CropHeight { get; set; }
public int CurrentImageCounter { get; set; }

private async Task ContinueCommandExecute()
{
    //crop the image
    if(CurrentImageCounter == _images.Count)
        return;
    else
    {
        var croppedImage = _cropImageService.CropImageWithRect(_images[CurrentImageCounter],
               new Rectangle(CropTopLeftX, CropTopLeftY, CropWidth, CropHeight));
        CurrentImageCounter++;

        //I want to change image here but it doesn't change even it is 2 way binding
        OriginalImage = _images[CurrentImageCounter];
        //I also want to set all 4 parameter of CropTopLeftX/Y/Width/Heigh here
    }
}

我已经在单击“ Continue按钮上将下一张图像设置为OriginalImage属性,但是它没有更改。 我也想设置CropTopLeftX / Y / Width / Heigh的所有4个参数

有人可以指导我吗?

您的视图模型需要实现INotifyPropertyChanged接口:

YourViewModel : BaseClass, INotifyPropertyChanged 

(...)

public event PropertyChangedEventHandler PropertyChanged = delegate { };

public void OnPropertyChanged([CallerMemberName]string propertyName="")
{
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

那么您需要将更改的事实通知所有绑定到您的属性的对象:

Image _originalImage;
public Image OriginalImage
{
    get => _originalImage;
    set
    {
         _originalImage = value;
         OnPropertyChanged();
    }
}

您需要在绑定到的每个属性设置器中调用OnPropertyChanged方法。

它不会更改,因为您没有通知更改。 您是ViewModel需要继承自INotifyPropertyChanged并在属性的设置器中实现通知。

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private Image originalImage;
    public Image OriginalImage
    {
        get => originalImage;
        set 
        {
            originalImage = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OriginalImage)); //Notify the property is changing.
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM