WPF ListView 未绑定到 ViewModel 属性
我正在尝试设置一个列表视图,在调用 Azure GraphAPI 后将加载用户列表。数据绑定之前的一切都有效。对 Graph 的调用有效,返回的数据有效,一切都没有问题。
我在视图中有一个列表视图设置:
<ListView ItemsSource="{Binding NoPicUsers}" >
<ListView.View>
<GridView>
<GridViewColumn
Header="Display Name"
Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding NoPicUsers.DisplayName}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
相应的 ViewModel 有以下代码:
public class ContentPanelHomeViewModel : ViewModelBase
{
private List<UserModel> _noPicUsers;//NotifyTask<List<UserModel>> _noPicUsers;
public List<UserModel> NoPicUsers
{
get
{
return _noPicUsers;
}
set
{
_noPicUsers = value;
//OnPropertyChanged Method is in ViewModelBase
OnPropertyChanged("NoPicUsers");
}
}
public ContentPanelHomeViewModel()
{
//NoPicUsers = new NotifyTask<List<UserModel>>.Create(GetNoPicUsersAsync());
//NoPicUsers = NotifyTask.Create(GetNoPicUsersAsync);
var users = GetNoPicUsersAsync();
}
private async Task<List<UserModel>> GetNoPicUsersAsync()
{
GraphServiceClient graphClient = await GraphAPIServices.SignInAndInitGraph(AzureAppInfo.UserReadAll);
List<UserModel> users = new List<UserModel>();
var listOfUsers = await graphClient.Users
.Request()
.Filter("accountEnabled eq true")
.Select("displayname, id")
.GetAsync();
foreach (var user in listOfUsers)
{
UserModel azureUser = new UserModel();
azureUser.DisplayName = user.DisplayName;
azureUser.ObjectID = user.Id;
users.Add(azureUser);
}
NoPicUsers = users;
return users;
}
}
我的列表视图不显示任何数据,我不明白为什么。 WPF 窗口加载时没有报告错误,也没有绑定错误报告,所以我不确定会出现什么问题?
编辑:我已经更新了我的代码。我正在实现 NugetPackage Nito.Mvvm。如果我在 GetNoPicUsersAsync() 内部设置 NoPicUsers,我会遇到同样的问题,即没有数据绑定到列表视图,WPF 窗口会喊出 NoPicUsers 属性在 UserModel 类型的对象上找不到。
因此,它似乎将我的 ViewModel 视为 UserModel 属性而不是 List 属性。什么会导致这样的情况呢?
在单步执行代码时,任务似乎永远不会完成。任务位于 Status = WaitingForActivation,Method =“{Null}”,Result =“{Not YetComputed}”。
I'm trying to setup a listview that, after a call to the Azure GraphAPI will load a list of users. Everything up to the binding of the data works. The call to Graph works, the returned data works, all without issue.
I have a listview setup in a view:
<ListView ItemsSource="{Binding NoPicUsers}" >
<ListView.View>
<GridView>
<GridViewColumn
Header="Display Name"
Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding NoPicUsers.DisplayName}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The corresponding ViewModel has the following code:
public class ContentPanelHomeViewModel : ViewModelBase
{
private List<UserModel> _noPicUsers;//NotifyTask<List<UserModel>> _noPicUsers;
public List<UserModel> NoPicUsers
{
get
{
return _noPicUsers;
}
set
{
_noPicUsers = value;
//OnPropertyChanged Method is in ViewModelBase
OnPropertyChanged("NoPicUsers");
}
}
public ContentPanelHomeViewModel()
{
//NoPicUsers = new NotifyTask<List<UserModel>>.Create(GetNoPicUsersAsync());
//NoPicUsers = NotifyTask.Create(GetNoPicUsersAsync);
var users = GetNoPicUsersAsync();
}
private async Task<List<UserModel>> GetNoPicUsersAsync()
{
GraphServiceClient graphClient = await GraphAPIServices.SignInAndInitGraph(AzureAppInfo.UserReadAll);
List<UserModel> users = new List<UserModel>();
var listOfUsers = await graphClient.Users
.Request()
.Filter("accountEnabled eq true")
.Select("displayname, id")
.GetAsync();
foreach (var user in listOfUsers)
{
UserModel azureUser = new UserModel();
azureUser.DisplayName = user.DisplayName;
azureUser.ObjectID = user.Id;
users.Add(azureUser);
}
NoPicUsers = users;
return users;
}
}
My listview does not display any data and I cannot figure out why. There are no reported errors and no binding errors reported when the WPF window loads so I'm not sure what would be the issue?
EDIT: I've updated my code. I'm implementing the NugetPackage Nito.Mvvm. I get the same problem of no data binding to my list view if I set my NoPicUsers inside of the GetNoPicUsersAsync() the WPF window yells saying NoPicUsers property no found on object of Type UserModel.
So it appears that it thinks my ViewModel as a UserModel property instead of a List property. What would cause that?
In stepping through the code the task never seems to complete. The Task sits at Status = WaitingForActivation, Method = "{Null}", Result = "{Not yet computed}".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是一个线程问题,其中 UI 不知道所做的更改,因为
Task
是在单独的线程上调用的,因为它没有等待。我建议使用由视图模型引发的异步事件,
如果在与 UI 相同的线程上调用
OnPropertyChanged
,它会触发 UI 更新。由于视图模型尝试更新后台线程上的属性,因此 UI 没有收到通知,因此不知道需要更新。通过在后台线程上完成繁重的工作,UI 在工作完成时保持响应。当任务返回到 UI 线程时,可以更新该属性,以便 UI 可以接收事件触发器来更新自身。
UI 中声明的绑定也存在问题。单元格模板需要绑定到项目的属性,而不是顶级属性
This is a threading issue where the UI is unaware of changes being made because the
Task
is being invoked on a separate thread since it is not awaited.I suggest using an async event raised by the view model
the
OnPropertyChanged
would have triggered the UI to update if it was invoked on the same thread as the UI. Because the view model trying to update the property on a background thread the UI was not getting the notification so was unaware that it needed to update.By doing the heavy lifting on a background thread the UI is kept responsive while the work is being done. When the task returns to the UI thread then the property can be updated so the UI can receive the event trigger to update itself.
There is also an issue with the binding declared in the UI. The cell template needs to bind to the property of the item, not the top level property