WPF ListView 未绑定到 ViewModel 属性

WPF ListView not Binding to ViewModel Property

我正在尝试设置一个列表视图,在调用 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 window 时没有报告错误,也没有报告绑定错误,所以我不确定会出现什么问题?

编辑:我更新了我的代码。我正在实施 NugetPackage Nito.Mvvm。如果我在 GetNoPicUsersAsync() 中设置我的 NoPicUsers,我会遇到同样的问题,即没有数据绑定到我的列表视图 WPF window 大喊说 NoPicUsers 属性 no found on object of Type UserModel.

所以它似乎将我的 ViewModel 视为 UserModel 属性 而不是列表 属性。什么会导致这种情况?

在逐步执行代码时,任务似乎从未完成。任务位于 Status = WaitingForActivation,Method =“{Null}”,Result =“{Not yet computed}”。

这是一个线程问题,UI 没有意识到所做的更改,因为 Task 正在单独的线程上调用,因为它没有被等待。

我建议使用视图模型引发的异步事件

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() {
        starting += onStarting;
        starting(this, EventArgs.Empty);
    }

    private event EventHandler starting = delegate { };
    private async void onStarting(object sender, EventArgs args) {
        starting -= onStarting; //optional

        // the following runs on background thread
        List<UserModel> users = await GetNoPicUsersAsync();

        // returned to the UI thread
        NoPicUsers = users; //notifies UI
    }

    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);
        }    
        return users;
    }

}

如果 UI 在与 UI 相同的线程上被调用,OnPropertyChanged 会触发 UI 更新。因为试图在后台线程上更新 属性 的视图模型 UI 没有收到通知,所以不知道它需要更新。

通过在后台线程上完成繁重的工作,UI 在工作完成时保持响应。当任务 returns 到 UI 线程时,属性 可以更新,因此 UI 可以接收事件触发器以更新自身。

UI 中声明的绑定也存在问题。单元格模板需要绑定到项目的属性,而不是顶层属性

<ListView ItemsSource="{Binding NoPicUsers}"  >
    <ListView.View>
        <GridView>
            <GridViewColumn
                Header="Display Name"
                Width="200">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding DisplayName}"></TextBlock>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>