Xamarin Forms - 强制控件从绑定中刷新值

Joh*_*ore 4 data-binding xamarin xamarin.forms

鉴于以下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; }
}
Run Code Online (Sandbox Code Playgroud)

绑定到页面...

<?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>
Run Code Online (Sandbox Code Playgroud)

当页面出现时,Label将获得文本"欢迎使用该应用程序".这非常有效,适合我们的计​​划,可以自定义和全球化我们的应用程序.然后在此示例中静态设置品牌字典,但在现实世界中,它由来自服务调用的数据初始化.

但是,如果用户想要将语言切换为西班牙语,我们需要将每个绑定标签更新为新值.重置品牌字典并用西班牙语翻译填充它很容易,但是我们如何强制控件从其绑定源中刷新?

我试图在这里避免双向数据绑定b/c我们不希望为控件的每个Text属性创建支持属性的代码开销.因此,我们绑定了价值字典.

回答

我接受了下面的答案,但我没有使用传统的财产制定者.相反,当用户想要切换不同的语言时,我们现在有一个集中处理程序,它重新填充我们的Dictionary,然后通知对Dictionary的更改.我们正在使用MVVMCross,但你可以翻译成标准表格......

    public MvxCommand CultureCommand
    {
        get
        {
            return new MvxCommand(async () =>
            {
                _brandingService.ToggleCurrentCulture();
                await ApplyBranding(); // <-- this call repopulates the Branding property
                RaisePropertyChanged(() => Branding);
            });
        }
    }
Run Code Online (Sandbox Code Playgroud)

Mar*_*ván 11

正如@BillReiss所提到的,你需要使用OnPropertyChanged事件从这个类继承NameEntryViewModel:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

并创建一个私有属性,您可以为您分配公共属性,如:

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

每当你设置Branding属性时,它都会让View知道有些东西发生了变化!有时如果你在背线上这样做,你必须使用Device.BeginInvokeOnMainThread()