【问题标题】:How to set two way binding for Image control in Xamarin.Forms?如何在 Xamarin.Forms 中为 Image 控件设置两种方式绑定?
【发布时间】:2018-04-05 13:56:06
【问题描述】:

我有一个带有图像的自定义视图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 个参数

有人可以指导我吗?

【问题讨论】:

    标签: c# xamarin.forms xamarin.ios


    【解决方案1】:

    您的视图模型需要实现 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 方法。

    【讨论】:

    • 嗨,Michal,我注意到,当我在 OriginalImage 中设置任何其他图像时,set 属性带有新的图像源,但它不会改变我屏幕上的图像。我需要更改MyPhotoView 中的任何内容吗?请建议
    【解决方案2】:

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

    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.
            }
        }
    }
    

    【讨论】:

    • 它不起作用。我刚刚应用了你的代码。如果我遗漏了什么,请提出建议。
    • @NanjiMange 尝试将绑定模式设置为 OneWay,看看它是否会改变。 {Binding OriginalImage, Mode=OneWay}
    • @NanjiMange 另外,发布整个 XAML (PhotoView) 代码,以便我可以准确地看到它绑定的内容。我假设您将 ViewModel 设置为 BindingContext 但无法判断。
    • 好的,MyPhotoView 中还有一件事,我设置了public static readonly BindableProperty OriginalImageProperty = BindableProperty.Create(nameof(OriginalImage), typeof (Image), typeof (MyPhotoView),null,BindingMode.TwoWay);。我需要在这里更改什么吗?
    • 您的 MyPhotoView 中根本不需要它,因为您有一个 ViewModel。您的视图绑定到 ViewModel;您编写的依赖属性用于自定义控件。删除它并只使用视图模型。 XAML 知道如何使用您编写的 DependencyProperties 绑定到其他 UserControls / CustomControls(但您没有正确使用它或者我根本不相信)并且 XAML 还知道如何绑定到 INotifyPropertyChanged 这是您的 ViewModel 中的内容.
    猜你喜欢
    • 2017-03-26
    • 2015-07-29
    • 1970-01-01
    • 2017-06-05
    • 1970-01-01
    • 1970-01-01
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多