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

Hello,

I have a custom view MyPhotoView with Image. I have set image on load. Now I want to change image on continue button click. I have tried to use TwoWay Binding and set value of Binding property but image doesn't change on the click of Continue button.

XAML:

<local:MyPhotoView x:Name="MyPhotoView"
                 OriginalImage="{Binding OriginalImage}"
                 CropTopLeftX="{Binding CropTopLeftX}"
                 CropTopLeftY="{Binding CropTopLeftY}"
                 CropWidth="{Binding CropWidth}"
                 CropHeight="{Binding CropHeight}" />

<Button Clicked="ContinueClicked" Text="Continue" FontSize="17" Command="{Binding ContinueCommand}" />

Custom Control MyPhotoView that used in XAML

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); }
    }
}

ViewModel

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

I have set next image to OriginalImage property on click Continue button but it doen't change. I also want to set all 4 parameter of CropTopLeftX/Y/Width/Heigh

Can anybody please guide me?

Best Answer

Answers

  • BradChase.2654BradChase.2654 USMember ✭✭✭

    What is Image? Is that the Image control? Why dont you inherit your MyPhotosView from Image instead? It doesnt seem like the Image control is ever being put into the layout. Also you will probably want to just change the image source on each click rather than the entire Image control. Another thing I noticed is you never want a dependency of Views/Controls in your ViewModel. I would have say a uri or string in the VM and let the control handle the rest.

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    Two-way binding on an Image doesn't make sense.
    Two-way binding is for items that could be changed by the user, and the update goes to the ViewModel, or could be a change at the ViewModel and needs to push to the UI.
    You can't have that with an Image. The UI can't change the Image source the same way a user can input a new value into a text Entry for example.

    So it doesn't make sense that you would have two-way binding. An Image would always be changed in the ViewModel property and that change would always be reflected in the UI.

  • developer007developer007 Member ✭✭

    @ClintStLaurent said:
    Two-way binding on an Image doesn't make sense.
    Two-way binding is for items that could be changed by the user, and the update goes to the ViewModel, or could be a change at the ViewModel and needs to push to the UI.
    You can't have that with an Image. The UI can't change the Image source the same way a user can input a new value into a text Entry for example.

    So it doesn't make sense that you would have two-way binding. An Image would always be changed in the ViewModel property and that change would always be reflected in the UI.

    Can you please suggest what should I do in this case? I have list of images that should show one by one by Continue button click till all images.

  • BradChase.2654BradChase.2654 USMember ✭✭✭
    edited April 2018

    You could have a list of URIs or strings and an items control to the list... Or if you have to change out the Image.Source then bind the source directly to the String on the VM with a converter.

    EDIT: I wanted to add that a good way to help not break MVVM is to separate out your VMs to their own library. And make sure to not reference Xamarin.Forms in that library.

  • developer007developer007 Member ✭✭

    @BradChase.2654 said:
    You could have a list of URIs or strings and an items control to the list... Or if you have to change out the Image.Source then bind the source directly to the String on the VM with a converter.

    EDIT: I wanted to add that a good way to help not break MVVM is to separate out your VMs to their own library. And make sure to not reference Xamarin.Forms in that library.

    I have list of images like List which I have send from previous ViewModel where all the images were taken from gallery(i.e /Users/Me/Library/Developer/CoreSimulator/Devices/3C26B8DD-1E37-47A0-B164-810AE3EA4A4D/data/Containers/Data/Application/05BE5988-4F9F-4E17-BCC2-1657D1E20209/Documents/IMG_0001.JPG")

    I have tried by changing source of the image of Custom Control as following but it really doesn't work.

    OriginalImage.Source= "/Users/bkp/Library/Developer/CoreSimulator/Devices/3C26B8DD-1E37-47A0-B164-810AE3EA4A4D/data/Containers/Data/Application/05BE5988-4F9F-4E17-BCC2-1657D1E20209/Documents/IMG_0001.JPG"

    Can you please suggest how can I change image of OriginalImage of ViewModel Property so it can reflect on Image of my XAML page that have MyPhotoView custom control?

    I have tried all but didn't get anything. Still on same stage.

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    @developer007 said:
    I have tried by changing source of the image of Custom Control as following but it really doesn't work.
    I have tried all but didn't get anything. Still on same stage.

    Sounds like you aren't doing binding correctly. If I had to guess I'd bet you use CLR properties instead of BindingPropery.

    You said you were trying to make a reusable control. Maybe this tutorial will help.
    https://redpillxamarin.com/2017/01/28/206-reusable-controls/

Sign In or Register to comment.