如何在双向绑定组合框(WPF)上调用异步操作
Posted
技术标签:
【中文标题】如何在双向绑定组合框(WPF)上调用异步操作【英文标题】:How to invoke async-operation on two-way bound Combobox (WPF) 【发布时间】:2018-07-03 13:45:33 【问题描述】:当从双向绑定控件(例如组合框(wpf 数据绑定))中选择项目时,处理运行异步操作的适当方法是什么?
当我有一个双向绑定属性(例如 ComboBox 上的 SelectedValue)时,我认为我不能使用 Stephen Cleary's NotifyTaskCompletion,因为当用户从下拉列表中选择一个值时,ComboBox 本身需要修改绑定的 Result属性,即Task的结果。
我想出的唯一可行的解决方案是从数据绑定设置器调用异步 Task 方法而不等待结果。这应该没问题,只要异步方法为正在执行的任何与 ui 相关的事情触发属性更改事件,并且任何异常都会相应地被拾取并传播到 ui,对吧?
我认为这将是异步 WPF 应用程序中的常见情况。你们是怎么处理这个问题的?
到目前为止我的解决方案:
<ComboBox
ItemsSource="Binding PossibleItems"
DisplayMemberPath="Name"
SelectedValue="Binding SelectedItem"/>
...
public Item SelectedItem
get return m_selectedItem;
set
m_selectedItem = value;
OnPropertyChanged();
InitializeAsyncAndFirePropertyChanged(); // async Task method not awaited - gives compiler warning CS4014
public async Task InitializeAsyncAndFirePropertyChanged(ObservableCollection<RFEnvironment> possibleRfEnvironments)
//should check this method for exceptions and propagate them to the UI via databinding
OtherDataBoundProperty = await GetSomeStringFromWebAsync();
public string OtherDataBoundProperty
get return m_otherDataBoundProperty;
set
m_otherDataBoundProperty = value;
OnPropertyChanged();
注意:我发现有人问过类似的问题,但没有一个涉及到控件(例如 Combobox)上的双向绑定。
【问题讨论】:
我遇到了类似的问题,但是不等待就运行异步是不够的。例外情况如何?但还没有找到更好的解决方案。 【参考方案1】:在使用 WCF 数据绑定时,我在属性设置器中调用 async
时遇到了类似的问题。
我的解决方案稍微好一点,因为在您的情况下,当InitializeAsyncAndFirePropertyChanged
发生异常时,不会抛出或捕获异常。修改后的代码如下。它使用任务延续来引发异常并引发OnPropertyChanged
。 OnPropertyChanged
电话可以留在原地,这取决于你的需要。
public class MyViewModel: INotifyPropertyChanged
private readonly TaskScheduler _uiScheduler;
public MyViewModel()
_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
public Item SelectedItem
get return m_selectedItem;
set
m_selectedItem = value;
InitializeAsyncAndFirePropertyChanged()
.ContinueWith(t =>
if (t.Exception != null)
throw t.Exception;
OnPropertyChanged();
, _uiScheduler);
public async Task InitializeAsyncAndFirePropertyChanged(ObservableCollection<RFEnvironment> possibleRfEnvironments)
//should check this method for exceptions and propagate them to the UI via databinding
OtherDataBoundProperty = await GetSomeStringFromWebAsync();
public string OtherDataBoundProperty
get return m_otherDataBoundProperty;
set
m_otherDataBoundProperty = value;
OnPropertyChanged();
.... other code to support INotifyPropertyChanged
【讨论】:
【参考方案2】:如果您使用的是功能性反应式 MVVM 框架,例如 ReactiveUI,您只需观察 SelectedItem
属性并在设置该属性时启动您想要的任何操作。例如:
this.WhenAnyValue(x => x.SelectedItem)
.Subscribe(async _ => await InitializeAsyncAndFirePropertyChanged());
属性本身应该启动后台操作,但视图模型可能会在设置属性时执行此操作。
更多信息请参考文档:https://reactiveui.net/docs/concepts/。
【讨论】:
这看起来很有趣,我可能会研究一下响应式UI,但现在我正在寻找一种使用普通 MVVM 和 WPF 解决这个问题的方法。 究竟解决什么问题?属性不能是异步的。 当用户从组合框下拉菜单中选择一个值时,如何最好地启动异步操作。我越看它,我认为没有神奇的美丽解决方案。我只需要确保 setter 立即返回并以某种方式触发异步方法。线索是确保异步方法在完成时调用适当的 propertyChange-calls,并处理可能由自身触发的任何错误,触发 propertyChange-calls 绑定到 UI 错误指示器的错误属性。 我已经回答过了;查看函数式编程并在视图模型中进行设置,而不是在属性本身中进行设置。另一种选择是简单地触发属性设置器中的异步操作,然后要么忘记结果,要么连接到异步方法完成后引发的某个事件。你是对的,这无论如何都不漂亮 :) ReactiveUI 和类似的库是有原因的。以上是关于如何在双向绑定组合框(WPF)上调用异步操作的主要内容,如果未能解决你的问题,请参考以下文章
extjs 组合框 afterrender() 一起调用导致异步 ajax 调用
WPF ObservableCollection 异步调用问题
wpf中mvvm的Command绑定后,如何在点击按钮的时候在viewmodel里面异步执行方法。