BindableProperty For Custom ContentView Not Being Set By Page's ViewModel

pmhart83pmhart83 USMember ✭✭✭
edited August 2016 in Xamarin.Forms

I have a menu button (assume there is a XAML file with a label that gets set when you call SetSubtitle(string)":

`
public partial class MenuRowGroupButton : ContentView
{

    public static readonly BindableProperty SubtitleProperty = BindableProperty.Create
    (
        propertyName: "Subtitle",
        defaultBindingMode: BindingMode.TwoWay,
        returnType: typeof(string),
        declaringType: typeof(MenuRowGroupButton),
        defaultValue: "",
        propertyChanged: handleOnSubtitlePropertyChanged
    );

    private static void handleOnSubtitlePropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        (bindable.BindingContext as MenuRowGroupButtonViewModel)?.SetSubtitle(newValue as string);
    }

    public MenuRowGroupButton()
    {
        InitializeComponent();
    }

}

`

In a XAML page:

`
<?xml version="1.0" encoding="UTF-8"?>

    <Grid>
        <forms:MenuRowGroupButton 
                Title="Button"
                Subtitle="{Binding ButtonSubtitle}" />
    </Grid>

</ContentPage>

`

While that XAML page has a ViewModel:

`
using System;
using System.ComponentModel;
using Prism.Mvvm;
using Xamarin.Forms;

namespace MyApp.Forms
{
    public class MasterDetailMenuPageViewModel : BindableBase, INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        public string ButtonSubtitle
        {
            get { return "test"; }
        }

    }

}

`

And my problem is that I can set "Subtitle" in the ContentPage XAML and it appears in the MenuRowGroupButton as expected. However when it comes from the Page's ViewModel, it's always null and no change events are triggered etc. I could do this using MVC or another way but I am trying to get it to work using MVVM.

If I set a normal label's text to "{Binding ButtonSubtile}" the text appears so I know the ViewModel of the page is hooked up. But no matter what I tried, the Page's ViewModel does not pass it's value to the button's BindableProperty.

Side note, if anyone knows why the "code" view on these forms leaves parts of my code out between the single quotes I'd like to know!

Posts

  • pmhart83pmhart83 USMember ✭✭✭

    Bump.

    I solved this using a "hacky" method. Basicly in the MasterDetailMenuPage.xaml.cs I added a handler like this:

    if(BindingContext is MasterDetailMenuPageViewModel) { var bc = (BindingContext as MasterDetailMenuPageViewModel); bc.PropertyChanged += handlePropertyChanged; }

    Then in the handler I update it like this:

    `
    public void handlePropertyChanged(object sender, PropertyChangedEventArgs e)
    {

        var bc = (BindingContext as MasterDetailMenuPageViewModel);
    
        if(bc != null)
        {
    
            (AllSongsButton.BindingContext as MenuRowGroupButtonViewModel)?.SetSubtitle(bc.AllSongsSubtitle);
            (AllSongsButton.BindingContext as MenuRowGroupButtonViewModel)?.SetSelected(bc.AllSongsIsSelected);
            (AllSongsButton.BindingContext as MenuRowGroupButtonViewModel)?.SetTapCommand(bc.AllSongsTapCommand);
    
            (OnDeviceButton.BindingContext as MenuRowGroupButtonViewModel)?.SetSubtitle(bc.OnDeviceSubtitle);
            (OnDeviceButton.BindingContext as MenuRowGroupButtonViewModel)?.SetSelected(bc.OnDeviceIsSelected);
            (OnDeviceButton.BindingContext as MenuRowGroupButtonViewModel)?.SetTapCommand(bc.OnDeviceTapCommand);
    
            (ImportedButton.BindingContext as MenuRowGroupButtonViewModel)?.SetSubtitle(bc.ImportedSubtitle);
            (ImportedButton.BindingContext as MenuRowGroupButtonViewModel)?.SetSelected(bc.ImportedIsSelected);
            (ImportedButton.BindingContext as MenuRowGroupButtonViewModel)?.SetTapCommand(bc.ImportedTapCommand);
    
        }
    
    }
    

    `

    Its manual and hackish but it works. I know things like the "Label" control just work so there must be something I am missing?

Sign In or Register to comment.