UI响应性并使用WPF中的“SelectedItem”ListView / ListBox

问题描述 投票:0回答:1

我有一些情况,我试图设计我的WPF .NET 4.0应用程序来处理ListBox / ListView中的SelectedItem的更改。

基本上我想查询其他数据以根据用户选择的内容填充ObservableCollection / DataGrid。我的问题是,通过将所有内容放在同一个线程上,响应性会受到影响,因为单击的项目仅在“SelectedItem”Setter中启动的任何代码完成时显示为选中,并且此“等待”不响应我的方式想要它。

正在查询的数据通常通过LINQ从同一个数据库填充ObservableCollection,这就是为什么一切都使用相同的UI线程。

理想情况下我想:

  1. 用户单击列表中的项目,该项目立即被选中,而不会感觉应用程序挂起。
  2. 要将“IsBusy”属性设置为true(用于绑定以更改某些控件的启用状态)。
  3. 开始查询其他数据并完成该操作后,应填充(例如)DataGrid,并将IsBusy返回false。

在“后台”中加载辅助数据来实现此目的的最佳方法是什么?我以前在WinForms中使用过BackgroundWorker,但我很想了解更多有关Dispatcher的信息,我认为这是正确的方向。

我的SelectedItem属性和这一样简单:

    public Employee SelectedEmployee
    {
        get
        {
            return mvSelectedEmployee;
        }

        set
        {
            mvSelectedEmployee = value;
            RaisePropertyChanged();

            IsBusy = true;
            QueryMyEmployeesAddressesAndOtherData(); //which takes sometimes 2 seconds
            IsBusy = false;
        }
    }

我希望用户知道某些事情正在发生,但尽管有一点点延迟。

谢谢。

c# wpf xaml mvvm observablecollection
1个回答
1
投票

使用async / await是实现此目的的最佳方法。您的特定情况的一个问题是属性设置器不能标记为async。但是,你可以从二传手中开出一个async void方法。这是一个简单的示例,无需更改代码库中的任何其他内容即可使用:

public Employee SelectedEmployee
{
    get
    {
        return mvSelectedEmployee;
    }

    set
    {
        mvSelectedEmployee = value;
        RaisePropertyChanged();
        UpdateSelectedEmployeeAsync();
    }
}

private async void UpdateSelectedEmployeeAsync()
{
    IsBusy = true;
    await Task.Run(() => QueryMyEmployeesAddressesAndOtherData());
    IsBusy = false;
}

但是你真正想要做的就是让QueryMyEmployeesAddressesAndOtherData异步“一直向下”。 Task.Run实际上更适合在后台运行CPU绑定操作,但听起来你的主要是IO绑定(等待一些查询执行)。无论您使用什么持久性框架,都很可能具有异步支持(如果不支持,请考虑更新为支持框架)。现在你可能最终得到这样的东西:

private async void UpdateSelectedEmployeeAsync()
{
    IsBusy = true;
    await QueryMyEmployeesAddressesAndOtherDataAsync();
    IsBusy = false;
}

private async Task QueryMyEmployeesAddressesAndOtherDataAsync()
{
    using (var ctx = new MyContext())
    {
        var queryResults = await ctx.EmployeeData.Where(t=>t.EmployeeId == SelectedEmployee.Id).ToArrayAsync();
        SelectedEmployeeDatas.Clear();
        foreach (var data in queryResults)
        {
            SelectedEmployeeDatas.Add(data);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.