简体   繁体   中英

Xamarin android with mvvm light : Textview binding only updates when a relaycommand is called

I setup a very simple app to get me started and trying things out. It has a label and two buttons. The buttons are linked to relaycommands in the main view model are used to send a message to a server using Mqtt which work as intended. The label is used to show part of the data received from the server. Everything seems to work fine except the labels won't update as soon as the message is received event though I can see in debugging that the property is set. The label will update as soon as I press one of the two buttons...

I'm new to the whole Xamarin android thing and have used mvvm light once in a WPF application.

Main Activity :

public partial class MainActivity
{
    // UI Elements 
    public TextView ScanInfoLabel { get; private set; }
    public Button UnlockButton { get; private set; }
    public Button RegisterButton { get; private set; }

    // Keep track of bindings to avoid premature garbage collection
    private readonly List<Binding> _bindings = new List<Binding>();

    // Get view model
    private MainViewModel mainViewModel { get { return App.Locator.Main;}}

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

        // Set view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        // Get the UI elements by ID
        ScanInfoLabel = FindViewById<TextView>(Resource.Id.ScanInfoLabel);
        UnlockButton = FindViewById<Button>(Resource.Id.UnlockButton);
        RegisterButton = FindViewById<Button>(Resource.Id.RegisterButton);

        // Set Bindings for textviews
        _bindings.Add(
                this.SetBinding(
                    () => mainViewModel.ScanInfoLabel,
                    () => ScanInfoLabel.Text));

        // Set the bindings for commands
        UnlockButton.SetCommand("Click", mainViewModel.UnlockCommand);
        RegisterButton.SetCommand("Click", mainViewModel.RegisterTagCommand);
    }

In Main view model :

// RelayCommands
public RelayCommand UnlockCommand;
public RelayCommand RegisterTagCommand;
public RelayCommand MqttConnectCommand;

// Bindable properties
private string _scanInfoLabel = "Test";
public string ScanInfoLabel
{
    get { return _scanInfoLabel; }
    set { Set(ref _scanInfoLabel, value); }
}

// New scan message received
private void RFIDScanReceived(RFID.Scan scan)
{
    ScanInfoLabel = BitConverter.ToString(scan.UID);
}

I would expect the label to show the data as soon as the mqtt message is received (which is then sent to the mainviewmodel using Messenger.Default.send<>() from mvvm light). But nothing is changed in the UI until I click on one of the buttons and then the correct information in displayed.

I don't really know where to start being new to xamarin android and none of my searches seemed to be of any help.

Any help will be appreciated, thanks!

ViewModels generally implement the INotifyPropertyChanged interface, which means that the class fires a PropertyChanged event whenever one of its properties changes. The data binding mechanism in Xamarin.Forms attaches a handler to this PropertyChanged event so it can be notified when a property changes and keep the target updated with the new value.

Solution:

Make you model inherit from INotifyPropertyChanged and add PropertyChanged inside the set part. Then the labels will update as soon as the value of ScanInfoLabel changed.

public class BaseViewModel : INotifyPropertyChanged
    {
        // Bindable properties
        private string _scanInfoLabel = "Test";
        public string ScanInfoLabel
        {
            get { return _scanInfoLabel; }
            set
            {
                _scanInfoLabel = ScanInfoLabel;

                PropertyChanged(this, new PropertyChangedEventArgs("ScanInfoLabel"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

You can refer: data-bindings-to-mvvm

Well I found out it was a threading issue since I set the property from a Messenger call. This apparently is not an issue in WPF which is why I was a bit stuck but using the DispatcherHelper did the trick.

// New scan message received
private void RFIDScanReceived(RFID.Scan scan)
{
    DispatcherHelper.CheckBeginInvokeOnUI(() => 
    {
        ScanInfoLabel = BitConverter.ToString(scan.UID);
    });
}

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