Asynchronous 如何从属性设置器调用异步函数?
我有一个wpf应用程序,它的Asynchronous 如何从属性设置器调用异步函数?,asynchronous,mvvm,Asynchronous,Mvvm,我有一个wpf应用程序,它的TextBox绑定到虚拟机中的actualpaginumber属性。我还有一个DataGrid绑定到显示给定页面的ObservableCollection。数据存储在数据库中。当我更改ActualPageNumber时,setter访问数据库,这可能会很慢。这就是为什么我需要一个异步setter,以保持gui的响应性 我知道没有异步设置程序: 我还发现了一些有用的东西,比如 我仍然在为如何继续处理这个案子而挣扎。AsyncEx库可以是解决方案,举个例子就好了 我只想通
TextBox
绑定到虚拟机中的actualpaginumber
属性。我还有一个DataGrid
绑定到显示给定页面的ObservableCollection
。数据存储在数据库中。当我更改ActualPageNumber
时,setter访问数据库,这可能会很慢。这就是为什么我需要一个异步setter,以保持gui的响应性
我知道没有异步设置程序:
我还发现了一些有用的东西,比如
我仍然在为如何继续处理这个案子而挣扎。AsyncEx库可以是解决方案,举个例子就好了
我只想通知用户页面实际上正在加载。如果我可以从setter调用async,我就可以这样做,但是我仍然不能在setter中使用wait
,因为它不是async
我还有一个DataGrid绑定到显示给定页面的ObservableCollection
这将是最困难的部分DataGrid
(以及DataTable
和friends)是使用同步API设计的,从未更新过以支持异步
我对DataGrid
不是很熟悉,但我想说您的选择是:
DataGrid
,例如,显示自定义控件的ListView
。然后可以显示加载微调器,因为您可以控制自定义控件。这有一些常见的模式,如NotifyTask
DataGrid
中的数据。我对DataGrid不太熟悉,不知道这是否真的可能,但值得研究一下DataGrid
的响应,此绑定属性可能会有所帮助:IsAsync=True
<DataGrid ItemsSource="{Binding MyCollection, IsAsync=True}"
但是要小心,虚拟化可能会捉弄你。例如,我有一个RowHeader(带有行号),当虚拟化开启时,值被置乱
2)关于数据绑定的异步setter:我使用的是自定义版本的IAsyncCommand
(请参阅)
我以两种方式使用该命令:a)从视图绑定到它(完全避免异步setter)或b)从setter启动它(不好)
示例:我创建了一个UpdateCommand
作为asynchcommand
并异步放置了我需要做的所有事情(比如从数据库获取值)。此命令中的所有内容都包装在一个“正在进行”控件的显示+隐藏中,就像控件一样,在我的例子中,是一个带有微调器的透明盖子+“请稍候…”,以防止其他用户操作(“屏幕”在执行任务时可见)。剥离样品:
....
public MainWindowViewModel()
{
UpdateCommand = AsyncCommand.Create(Update); // our own custom implementation of AsyncCommand
}
....
public AsyncCommand UpdateCommand { get; }
internal async Task Update(object arg)
{
await SafeWrapWithWaitingScreenAsync(async () =>
{
var value = (int)arg; // or the ActualPageNumber, if used from a1)
var data = await GetDataFromDb(value).ConfigureAwait(false);
...// fill in MyCollection (which is the DataGrid's ItemsSource) using the data
OnPropertyChanged(nameof(MyCollection));// if still needed
}).ConfigureAwait(false);
}
....
public async Task SafeWrapWithWaitingScreenAsync(Func<Task> action)
{
DisplayWaitingScreen = true; //Visibility of the "Waiting screen" binds to this
try
{
await action().ConfigureAwait(false);
}
catch (Exception ex)
{
HandleException(ex); // display/log ex
}
finally
{
DisplayWaitingScreen = false;
}
}
b)不确定这是否正确,但在使用NotifyTaskCompletion
(我将来可能会使用)查看setter之前,我启动了如下命令:
private int actualPageNumber;
public int ActualPageNumber
{
get => actualPageNumber;
set
{
actualPageNumber = value;
OnPropertyChanged(); //the sync way
UpdateCommand.Execute(value);
}
}
谢谢@Stephen显然我认为选项1将是答案。我试试看。我只是想知道,在WPF中,绑定属性设置器不能异步的原因是什么。在我的程序中,有几个属性设置程序应该启动DB操作(更改页面大小,更改过滤器)。如果我可以在这些设置器中简单地使用异步操作,我也可以等待它们,那就太好了。@IstvanHeckl:Property setter根据C语言规范返回
void
。
<TextBox Text="{Binding ActualPageNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Key="Return" Command="{Binding UpdateCommand}" CommandParameter="{Binding ActualPageNumber}" />
<KeyBinding Key="Enter" Command="{Binding UpdateCommand}" CommandParameter="{Binding ActualPageNumber}" />
</TextBox.InputBindings>
</TextBox>
private int actualPageNumber;
public int ActualPageNumber
{
get => actualPageNumber;
set
{
actualPageNumber = value;
OnPropertyChanged(); //the sync way
UpdateCommand.Execute(value);
}
}