如何在双向绑定组合框(WPF)上调用异步操作

如何在双向绑定组合框(WPF)上调用异步操作,wpf,asynchronous,combobox,properties,async-await,Wpf,Asynchronous,Combobox,Properties,Async Await,当从双向绑定控件(如combobox(wpf数据绑定))中选择项时,处理运行异步操作的适当方法是什么 当我有双向绑定属性(例如ComboBox上的SelectedValue)时,我认为我不能使用,因为当用户从下拉列表中选择一个值时,ComboBox本身需要修改绑定结果属性,这是任务的结果 我提出的唯一可行的解决方案是在不等待结果的情况下从数据绑定setter调用异步任务方法。只要async方法为正在执行的任何与ui相关的操作触发一个属性更改事件,并且任何异常都会被拾取并相应地传播到ui,就可以了

当从双向绑定控件(如combobox(wpf数据绑定))中选择项时,处理运行异步操作的适当方法是什么

当我有双向绑定属性(例如ComboBox上的SelectedValue)时,我认为我不能使用,因为当用户从下拉列表中选择一个值时,ComboBox本身需要修改绑定结果属性,这是任务的结果

我提出的唯一可行的解决方案是在不等待结果的情况下从数据绑定setter调用异步任务方法。只要async方法为正在执行的任何与ui相关的操作触发一个属性更改事件,并且任何异常都会被拾取并相应地传播到ui,就可以了,对吗

我假设这是异步WPF应用程序中的常见情况。你们是怎么做到的

到目前为止,我的解决方案是:

<ComboBox 
        ItemsSource="{Binding PossibleItems}"
        DisplayMemberPath="Name"
        SelectedValue="{Binding SelectedItem}"/>

public Item SelectedItem
{
获取{return m_selectedItem;}
设置
{
m_selectedItem=值;
OnPropertyChanged();
InitializeAsyncAndFirePropertyChanged();//未等待异步任务方法-向编译器发出警告CS4014
}
}
公共异步任务InitializeSyncdFirePropertyChanged(ObservableCollection-PossiblerEnvironments)
{
//应检查此方法是否存在异常,并通过数据绑定将其传播到UI
OtherDataBoundProperty=等待GetSomeStringFromWebAsync();
}
公共字符串OtherDataBoundProperty
{
获取{return m_otherDataBoundProperty;}
设置
{
m_otherDataBoundProperty=值;
OnPropertyChanged();
}
}

注意:我发现了类似的问题,但没有一个解决了组合框等控件的双向绑定问题。

如果您使用的是功能性反应式MVVM框架,如,您只需观察
SelectedItem
属性,并在设置属性时启动任何您想要的操作。e、 g:

this.WhenAnyValue(x => x.SelectedItem)
    .Subscribe(async _ => await InitializeAsyncAndFirePropertyChanged());
属性本身应该启动后台操作,但在设置属性时,视图模型可能会这样做


有关更多信息,请参阅文档:。

我在使用WCF数据绑定时遇到了与
async
调用属性setter类似的问题。 我的解决方案稍微好一点,因为在您的例子中,当InitializeAsyncAndFirePropertyChanged中发生异常时,不会抛出或捕获任何异常。修改后的代码如下。它使用任务继续引发异常并引发
OnPropertyChanged
OnPropertyChanged
call可以保留在原始位置,这取决于您的需要

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
}
公共类MyViewModel:INotifyPropertyChanged
{
专用只读任务调度器_uiScheduler;
公共MyViewModel()
{
_uiScheduler=TaskScheduler.FromCurrentSynchronizationContext();
}
公共项目选择项
{
获取{return m_selectedItem;}
设置
{
m_selectedItem=值;
初始化SyncdFirePropertyChanged()
.ContinueWith(t=>
{
if(t.Exception!=null)
{
抛出t异常;
}
OnPropertyChanged();
}),;
}
}
公共异步任务InitializeSyncdFirePropertyChanged(ObservableCollection-PossiblerEnvironments)
{
//应检查此方法是否存在异常,并通过数据绑定将其传播到UI
OtherDataBoundProperty=等待GetSomeStringFromWebAsync();
}
公共字符串OtherDataBoundProperty
{
获取{return m_otherDataBoundProperty;}
设置
{
m_otherDataBoundProperty=值;
OnPropertyChanged();
}
}
..支持INotifyPropertyChanged的其他代码
}

这看起来很有趣,我可能会在某个时候研究reactiveUI,但现在我正在寻找一种方法,用普通MVVM和WPF解决这个问题。具体解决什么?属性不能是异步的。当用户从组合框下拉列表中选择值时,如何最好地启动异步操作。我越看它,我就越觉得没有神奇的美丽的解决方案。我只需要确保setter立即返回,并以某种方式触发一个异步方法。线索是确保async方法在完成时调用适当的propertyChange调用,并处理其自身触发propertyChange调用绑定到UI错误指示器的错误属性时可能发生的任何错误;研究函数式编程,并在视图模型中设置它,而不是在属性本身中设置它。另一种选择是在属性setter中简单地触发异步操作,然后忘记结果,或者连接到异步方法完成后引发的某个事件。您是对的,这在任何方面都不漂亮:)ReactiveUI和类似的库是有原因的。我遇到了类似的问题,但不等待就运行异步是不够的。例外情况如何?但还没有找到更好的解决办法。
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
}