C# 服务完成后属性未更新
我正试图了解Xamarin.Forms中的数据绑定。我已经阅读了大量的指南并使用了一些示例,现在我正在尝试实现一些我自己的基本绑定 我有一个字符串文件,其中声明了一个空变量:C# 服务完成后属性未更新,c#,xamarin.forms,data-binding,C#,Xamarin.forms,Data Binding,我正试图了解Xamarin.Forms中的数据绑定。我已经阅读了大量的指南并使用了一些示例,现在我正在尝试实现一些我自己的基本绑定 我有一个字符串文件,其中声明了一个空变量: public static class Strings { public static string UserDisplayName; } 在加载my View时,它运行一个异步函数从Azure SQL DB获取数据,然后填充字符串 Strings.UserDisplayName = user.FirstName
public static class Strings
{
public static string UserDisplayName;
}
在加载my View时,它运行一个异步函数从Azure SQL DB获取数据,然后填充字符串
Strings.UserDisplayName = user.FirstName;
在我的视图页面中,我已将标签绑定到变量userDisplayNm
编辑:
谢谢你的回复。根据下面的回复,我想我已经接近了,这是我现在得到的,尽管MenuViewModel.LoadAsync抛出了一个由于其保护级别而无法访问的错误,所以我还不能编译来检查它。这就是你的建议吗&关于保护级别问题有什么想法吗
字符串文件:
public static class Strings
{
public static string UserDisplayName;
}
视图模型:
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;
}
}
}
}
视图:
因此,如果您正在寻找有关MVVM的指导,您应该知道,通常您会将依赖项放在视图模型构造函数中,这里是Azure服务 此外,您还可以使用现有的MVVM框架,使事情变得简单,如或 但是,如果您想要获得完整的版本,您也可以从查看代码隐藏中调用您的vm代码 因此,我建议对MenuViewModel进行以下修改:
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;
}
}
}
}
然后在您的视图中查看代码隐藏:
void OnAppearing()
{
_menuViewModel.LoadAsync();
}
要解决以下问题:由于其保护级别而无法访问,可以尝试在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;
}
其效果是:
Strings.UserDisplayName类需要实现INotifyPropertyChanged,然后您需要一个字符串实例,但您不能,因为它是静态的……让我们来看看。我已经编辑了我的原始问题,以纳入我希望的建议,但它仍然抛出错误,因此我还无法编译以进行检查。这是否符合你的建议?我理解正确了吗?另外,值得补充的是,我不想把它放在一个静态字符串中,这只是我处理它的方式。我很乐意绑定一个基本属性,这样当同步运行或失败时,它只显示欢迎,当它完成时,它会更新为显示欢迎,Stephen
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();
}
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;
}
<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();
}
}