服务完成后媒体资源未更新

时间:2019-08-23 14:13:12

标签: c# xamarin.forms data-binding

我正在努力弄清Xamarin.Forms中的数据绑定。我已经阅读了许多指南并使用了一些示例,现在我正在尝试实现一些自己的基本绑定。

我有一个Strings文件,其中声明了一个空变量:

public static class Strings
{
    public static string UserDisplayName;
}

在加载View时,它运行一个异步函数以从Azure SQL数据库中获取数据,然后填充字符串

Strings.UserDisplayName = user.FirstName;

在查看页面中,我已将标签绑定到变量userDisplayNm

<Label Text="{Binding UserDisplayNm}"></Label>

在我的ViewModel中,我具有以下设置UserDisplayNm的功能,但是它只返回“ Welcome,”。同步服务完成且Strings.UserDisplayname值更改后,如何才能再次触发它?我想我缺少指向PropertyChanged事件的链接?

    namespace Travel_Comp.ViewModels
    {
        public sealed class MenuViewModel : INotifyPropertyChanged
        {
        public event PropertyChangedEventHandler PropertyChanged;

        public MenuViewModel()
        {
            this.UserDisplayNm = Strings.UserDisplayName;
        }

        public string UserDisplayNm
        {
            set
            {
                if (Strings.UserDisplayName != value)
                {
                    value = Strings.UserDisplayName;

                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("UserDisplayNm"));
                    }
                }
            }
            get
            {
                return "Welcome, " + Strings.UserDisplayName;
            }
        }

    }
}

编辑:

感谢您的答复。我想根据下面的答复我正在接近,这是我现在得到的,尽管MenuViewModel.LoadAsync()抛出错误“由于其保护级别而无法访问”,所以我无法编译进行检查还没完成。这是您的建议以及有关保护级别问题的任何想法吗?

字符串文件:

public static class Strings
{
    public static string UserDisplayName;
}

ViewModel:

namespace Travel_Comp.ViewModels
{
    public sealed class MenuViewModel : INotifyPropertyChanged
    {
        //Azure sync process
        ServerManager manager;
        public event PropertyChangedEventHandler PropertyChanged;


        public MenuViewModel()
        {
            //Initial set of UserDisplayNm 
            this.UserDisplayNm = Strings.UserDisplayName;
        }

        async void LoadAsync()
        {
            try
            {
                //Run process to populate Strings.UserDisplayNm, set Syncitems to true to sync with Server
                foreach (var user in await manager.GetUsersAsync(syncItems: true))
                {
                    Strings.UserDisplayName = user.FirstName;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error while retrieving user name: {e}");
            }
        }

        public string UserDisplayNm
        {
            set
            {
                if (Strings.UserDisplayName != value)
                {
                    value = Strings.UserDisplayName;

                    if (PropertyChanged != null)
                    {
                        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UserDisplayNm)));
                    }
                }
            }
            get
            {
                return "Welcome, " + Strings.UserDisplayName;
            }
        }

    }
}

查看:

protected override async void OnAppearing()
{
    base.OnAppearing();

    ViewModels.MenuViewModel.LoadAsync();

}

2 个答案:

答案 0 :(得分:1)

因此,如果您正在寻找有关MVVM的指导,则应该知道通常将依赖项放在视图模型构造函数中,这里是Azure服务。

您还可以使用现有的MVVM框架,例如PrismFreshMVVM

但是,如果您想使用完整的香草,还可以从后面的视图代码中调用您的vm代码。

因此,我建议对您的MenuViewModel进行此修改:

private IAzureService _azureService;
private string _userDisplayNm;

public MenuViewModel(IAzureService azureService)
{
    _azureService = azureService;
}

public string UserDisplayNm
{
    get
    {
        return _userDisplayNm;
    }
    set
    {
        if (_userDisplayNm != value)
        {
            _userDisplayNm = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UserDisplayNm)));
        }
    }
}

public async void LoadAsync()
{
    try
    {
        UserDisplayNm = await _azureService.GetUserName();
    }
    catch (Exception exception)
    {
        Debug.WriteLine($"Error while retrieving user name: {exception}")
    }
}

然后在您后面查看代码:

void OnAppearing()
{
    _menuViewModel.LoadAsync();
}

答案 1 :(得分:0)

要解决问题:Inaccessible due to its protection level,您可以尝试在public的功能之前添加LoadAsync访问修饰符。

public async void LoadAsync(){
   //....
  }

我已经创建了一个简单的演示来模拟您的代码。

主要代码是:

 public sealed class TestModel: INotifyPropertyChanged
{

 //*******************************************
    string _userDisplayName;

    public string UserDisplayName {
        set { SetProperty(ref _userDisplayName, value); }

        get { return _userDisplayName; }
    }

    public async void LoadAsync()
    {
        try
        {
            UserDisplayName = "updated value: Angela";

            Strings.UserDisplayName = UserDisplayName;
        }
        catch (Exception exception)
        {
            Debug.WriteLine($"Error while retrieving user name: {exception}");
        }
    }


    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

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

    public event PropertyChangedEventHandler PropertyChanged;
}

xaml

 <Label Text="{Binding UserDisplayName }" BackgroundColor="Yellow" 
        VerticalOptions="Center" HorizontalOptions="Fill"  HeightRequest="50" />
 <Button  Text="update the Label value"  Clicked="Button_Clicked"/>

并像这样使用:

public partial class MyPage1 : ContentPage
{
    TestModel model;

    public MyPage1 ()
    {
        InitializeComponent ();

        model = new TestModel();
        BindingContext = model;       
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        model.LoadAsync();
    }
}

效果是: enter image description here