Xamarin Forms - force a control to refresh value from binding

18,350

As @BillReiss mentioned you need to use the OnPropertyChanged event inherit the NameEntryViewModel from this class:

public class BaseViewModel : INotifyPropertyChanged
{

    protected BaseViewModel ()
    {

    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler (this, new PropertyChangedEventArgs (propertyName));
    }
}

And create a private property that you can assign to you public property something like:

Dictionary<string, string> _branding = new Dictionary<string, string>();
public Dictionary<string, string> Branding
{
    get
    {
        return _branding;
    }
    set
    {
        _branding = value;
        OnPropertyChanged(nameof(Branding));
    }
}

And with this every time you set the Branding property it will let the View know that something changed! Sometimes if you are doing this on a back thread you have to use Device.BeginInvokeOnMainThread()

Share:
18,350

Related videos on Youtube

John Livermore
Author by

John Livermore

Updated on July 01, 2022

Comments

  • John Livermore
    John Livermore about 2 years

    Given the following ViewModel...

    public class NameEntryViewModel 
    {
        public NameEntryViewModel()
        {
            Branding = new Dictionary<string, string>();
    
            Branding.Add("HeaderLabelText", "Welcome to the app");
        }
    
        public Dictionary<string, string> Branding { get; set; }
    }
    

    Bound to the page...

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="Monaco.Forms.Views.NameEntryPage">
    
            <Label Text="{Binding Branding[HeaderLabelText]}" />
    
    </ContentPage>
    

    When the page comes up the Label will get the text 'Welcome to the app'. This works great and fits into our plan for being able to customize and globalize our app. Then Branding dictionary is statically set in this example, but in the real world it is initialized by data from a service call.

    However, should the user want to switch the language to Spanish, we would need each bound label to update to the new value. It's easy enough to reset the Branding dictionary and fill it with Spanish translations, but how can we force the controls to refresh from their bound sources?

    I am trying to avoid two-way data binding here b/c we don't want the code overhead of creating a backing property for each Text property of the controls. Hence we are binding to a dictionary of values.

    ANSWER

    I accepted the answer below, but I didn't use a traditional property setter. Instead when a user wants to toggle a different language, we now have a centralized handler that repopulates our Dictionary and then notifies of the change to the Dictionary. We are using MVVMCross, but you can translate to standard forms...

        public MvxCommand CultureCommand
        {
            get
            {
                return new MvxCommand(async () =>
                {
                    _brandingService.ToggleCurrentCulture();
                    await ApplyBranding(); // <-- this call repopulates the Branding property
                    RaisePropertyChanged(() => Branding);
                });
            }
        }
    
    • Bill Reiss
      Bill Reiss over 7 years
      You can raise the PropertyChanged event on the Branding property and it will refresh anything that binds to Branding or any Binding containing Branding in its path.