简体   繁体   中英

Bind a custom view to page model in xamarin forms

I am trying to create a custom view that will be used as a header in some of the pages in the application. A custom view has a button to save info, and an image to show if the info was saved, but I can also receive info from the API if the info was saved. (this is a simplified version of the scenario)

So, I have MainPage.xaml (any page that will use the custom view)

ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:Messages"
         xmlns:controls="clr-namespace:Messages.Controls"
         x:Class="Messages.MainPage">
<StackLayout Spacing="5">

    <controls:HeaderMenu x:Name="menu" HorizontalOptions="FillAndExpand" VerticalOptions="Start" SaveCommand="{Binding MyCommand}" IsControlClosed="{Binding ControlClosedValue, Mode=TwoWay}" />

    .....

</StackLayout>

MainPageViewModel.cs

public class MainPageViewModel : INotifyPropertyChanged
{
    public ICommand MyCommand { get; set; }

    private bool _controlClosedvalue;

    public bool ControlClosedValue
    {
        get => _controlClosedvalue;
        set
        {
            _controlClosedvalue = value;
            OnPropertyChanged(nameof(ControlClosedValue));
        }
    }

    public MainPageViewModel()
    {
        MyCommand = new Command(MyCommandExecute);
        _controlClosedvalue = false;
    }

    private void MyCommandExecute()
    {
        // do stuff

        _controlClosedvalue = true; //change value to change the value of control
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

HeaderMenu.xaml

<Grid>   

<Image Source="save.png" HeightRequest="25" WidthRequest="25">
                    <Image.GestureRecognizers>
                        <TapGestureRecognizer NumberOfTapsRequired="1" Tapped="SaveImage_OnTapped" />
                    </Image.GestureRecognizers>
                </Image>

 <Image  IsVisible="{Binding IsControlClosed}" Source="check.png" HeightRequest="30" WidthRequest="30" />

HeaderMenu.xaml.cs

public partial class HeaderMenu : ContentView
{
    public HeaderMenu ()
    {
        InitializeComponent();
        imgControlClosed.BindingContext = this;
    }

    public static readonly BindableProperty SaveCommandProperty =
        BindableProperty.Create(nameof(SaveCommand), typeof(ICommand), typeof(HeaderMenu));

    public static readonly BindableProperty IsControlClosedProperty =
        BindableProperty.Create(nameof(IsControlClosed), typeof(bool), typeof(HeaderMenu), false, BindingMode.TwoWay, null, ControlClosed_OnPropertyChanged);

    public ICommand SaveCommand
    {
        get => (ICommand) GetValue(SaveCommandProperty);
        set => SetValue(SaveCommandProperty, value);
    }

    public bool IsControlClosed
    {
        get => (bool) GetValue(IsControlClosedProperty);
        set => SetValue(IsControlClosedProperty, value);
    }

    private static void ControlClosed_OnPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is HeaderMenu control)
        {
            control.imgControlClosed.IsVisible = (bool)newValue;
        }
    }

    private void SaveImage_OnTapped(object sender, EventArgs e)
    {
        if (SaveCommand != null && SaveCommand.CanExecute(null))
        {
            SaveCommand.Execute(null);
        }
    }
}

So, what I need is that when the save command is tapped to execute some code in the page that is using control, and binding of SaveCommand works as expected. But after the code is executed, or in some different cases, I wish to change the property in the page model and this should change the property on the custom view, but this does not work.

Does anyone know what is wrong with this code?

If I just put True or False when consuming control it works.

<controls:HeaderMenu x:Name="menu" HorizontalOptions="FillAndExpand" VerticalOptions="Start" SaveCommand="{Binding MyCommand}" IsControlClosed="True" />

But it does not work when binding it to the property.

I have found out what an issue was. A stupid mistake, I was setting the value of the variable instead of property.

In the main page view model, instead of

_controlClosedvalue = false; // or true

it should be

ControlClosedValue = false; // or true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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