NaSt
NaSt

Reputation: 311

MVVMCross binding - How to change the visibility of object

I need to learn how to bind and change the property of elements.

I should change the visibility of element by clicking the button

I have Hello.axml with different elements.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<TextView
    android:textSize="16sp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    local:MvxBind="Text Strings[VerificationPhoneText]" />
<TextView
    android:textSize="16sp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    local:MvxBind="Text Variable01" />
<Button
    android:id="@+id/enterButton"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    local:MvxBind="Text Strings[EnterButton]; Click ClickCommand" />
<GestureOverlayView
    android:layout_height="284dp"
    android:layout_width="280dp"
    android:background="#FAFAFA"
    android:layout_marginLeft="40dp"
    android:layout_marginRight="40dp"
    android:layout_marginTop="114dp"
    local:MvxBind="Visibility Visibility(MyProperty)">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hello World" />
    <ImageView
        android:src="@mipmap/ic_check_circle_black_48dp"
        android:layout_marginLeft="95dp"
        android:layout_marginRight="95dp"
        android:layout_marginTop="103dp" />
</GestureOverlayView>

I have installed Visibility Plugin:

PM> Install-Package MvvmCross.Plugin.Visibility -Version 5.6.3

And edited my HelloViewModel.cs:

     using MvvmCross.Core.ViewModels;
     using System.Windows.Input;

namespace My.Project.Core.ViewModels
{
    public class HelloViewModel : BaseViewModel
    {
        private bool _myProperty;

        public bool MyProperty
        {
        get
        {
           return _myProperty;
        }
        set
        {
           _myProperty = value;
           RaisePropertyChanged();
      }
  }

        public ICommand ClickCommand => new MvxCommand(() =>
        {
            MyProperty = !MyProperty;
        });
    }
}

But I still have a problem - all elements are visible at the beginning and the button doesn't work.

UPD. My HelloView.cs:

using Android.App;

    namespace My.Project.Droid.Views
{
    [Activity]
    public class HelloView:BaseView
    {
        protected override int LayoutResource => Resource.Layout.HelloView;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
        }
    }
}

Please help me learn it!

Upvotes: 3

Views: 3858

Answers (2)

fmaccaroni
fmaccaroni

Reputation: 3916

As @c.lamont.dev says Visibility is managed as a plugin (another package) of MvvmCross: MvvmCross.Plugin.Visibility which you have to add in the PCL and in every platform you want to use it.

Even though what @miechooy works, it can be improved firstly as @c.lamont.dev in the comment by using directly the Visbiility converters provided by the plugin, i.e. MvxVisibilityValueConverter and MvxInvertedVisibilityValueConverter; they allow us to directly bind to a ViewModel property with that converter and it internally converts the ViewModel property's value to the correct value of Visibility in our platform View, e.g. in Android it converts from the ViewModel's property value to a ViewStates.

It also does a preconversion from whatever type the property is to visibility: so let's say instead of a bool you have an Object like Client, then if you bind with that converter to that property directly it will return Visible if the Client is not null and Collapsed otherwise (it applies to iOS too returning false or true for the Hidden property).

Example of binding:

<android.support.v7.widget.CardView
        android:layout_margin="5dp"
        style="@style/Widget.CardContent"
        local:MvxBind="Visibility Visibility(MyProperty)"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    ...
</android.support.v7.widget.CardView>

And to change your Visibility by clicking on the button you have to change your property (as @miechooy stated) and command a bit:

private bool _myProperty;
public bool MyProperty
{
    get
    {
       return _myProperty;
    }
    set
    {
       _myProperty = value;
       RaisePropertyChanged();
    }
}

public ICommand ClickToToggleMyPropertyVisibilityCommand => new MvxCommand(() =>
{
    MyProperty = !MyProperty;
});

Now, let's say you want to have you own converter because you have a more complicated logic, then you can inherit from MvxBaseVisibilityValueConverter<T> where you can return a MvxVisibility which is the object that MvvmCross uses to act as an abstraction of how the platform manage Visibility and therefore it can manage it from the PCL directly, sharing more code between the platforms.

Let's jump to an example: Having a ViewModel with a MyClient Property of type Client:

public class Client
{
     public string Name { get; set;}
     public bool IsActive { get; set; }
}

public class MyVM : MvxViewModel
{
    ...
    private Client _myClient;
    public Client MyClient
    {
       get
       {
           return _myClient;
       }
       set
       {
           _myClient = value;
           RaisePropertyChanged(() => MyClient);
       }
    }

    ...
}

You would like to show in your view only the client if it is active and it's name is not "Admin" so you'd need a custom visibility converter:

public class MyOwnVisibilityConverter : MvxBaseVisibilityValueConverter<Client>
{
    protected override MvxVisibility Convert(Client value, object parameter, CultureInfo culture)
    {
        return value.IsActive && value.Name != "Admin" ? MvxVisibility.Visible : MvxVisibility.Collapsed;
    }
}

finally in your View:

<android.support.v7.widget.CardView
        android:layout_margin="5dp"
        style="@style/Widget.CardContent"
        local:MvxBind="Visibility MyOwnVisibility(MyClient)"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

HIH

Upvotes: 5

miechooy
miechooy

Reputation: 3422

As described in comment. MvvmCross already created Visibility binding. There is an example:

 <android.support.v7.widget.CardView
            android:layout_margin="5dp"
            style="@style/Widget.CardContent"
            local:MvxBind="Visibility MyProperty, Converter=BooleanToVisibilty"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
</android.support.v7.widget.CardView>

Just declare proeprty in you view model

  public bool MyProperty
        {
            get
            {
                return _myProperty;
            }
            set
            {
                _myProperty = value;
                RaisePropertyChanged();
            }
        }

And finally craete BooleanToVisiblityConverter:

 public class BooleanToVisibiltyValueConverter : MvxValueConverter<bool, ViewStates>
    {
        protected override ViewStates Convert(bool value, Type targetType, object parameter, CultureInfo culture)
        {
            return value ? ViewStates.Visible : ViewStates.Gone;
        }
    }

Upvotes: 2

Related Questions