我正在努力弄清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();
}
答案 0 :(得分:1)
因此,如果您正在寻找有关MVVM的指导,则应该知道通常将依赖项放在视图模型构造函数中,这里是Azure服务。
您还可以使用现有的MVVM框架,例如Prism或FreshMVVM。
但是,如果您想使用完整的香草,还可以从后面的视图代码中调用您的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();
}
}