C# MVVM和异步属性

C# MVVM和异步属性,c#,wpf,mvvm,async-await,C#,Wpf,Mvvm,Async Await,我有一个具有以下属性的ViewModel public Employee SelectedEmployee { get { return _selectedEmployee; } set { if (value == _selectedEmployee) return; _selectedEmployee = value;

我有一个具有以下属性的ViewModel

public Employee SelectedEmployee
        {
            get { return _selectedEmployee; }
            set
            {
                if (value == _selectedEmployee) return;
                _selectedEmployee = value;

                if (_selectedEmployee != null)
                {
                    StaffHolidaysViewModel.HolidayAllowance = _staffDataService.EmployeeHolidayAllowance(_selectedEmployee.Id);
                    FireEmployeeSelectedMessage(SelectedEmployee.Id);
                }

                RaisePropertyChanged();
                RaisePropertyChanged(nameof(Allowance));
                RaisePropertyChanged(nameof(Taken));
                RaisePropertyChanged(nameof(Remaining));
                RaisePropertyChanged(nameof(TotalAbsences));
                RaisePropertyChanged(nameof(TotalSick));
                RaisePropertyChanged(nameof(TotalNonSickAbsences));
                RaisePropertyChanged(nameof(SelectedEmployeeLeavingDate));
                UpdateCanExecuteChanged();
            }
        }
线路

StaffHolidaysViewModel.HolidayAllowance = _staffDataService.EmployeeHolidayAllowance(_selectedEmployee.Id);
包含对我要使其异步的方法的调用。我不知道如何才能做到这一点,因为SelectedEmployee是一个绑定属性

<ComboBox Name="StaffMembers" ItemsSource="{Binding FilteredEmployees}" SelectedItem="{Binding SelectedEmployee}" Width="200" BorderThickness="1" BorderBrush="DimGray">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name}"/>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>

因为它是一个属性,所以我无法将其类型设置为
Task


对于异步绑定的MVVM属性,建议采用什么方法?或者说这是不可能的?

从技术上讲,让属性执行异步任务并不是一种理想的方法,因为它们需要返回一个值

为什么?让我们从另一个角度来看:

异步意味着UI线程将不会停止(处理时UI不会挂起),而主处理线程将等待操作完成并获得结果(考虑到您正在使用的是
wait

定义绑定时,UI直接依赖于使用wait的数据的属性,这意味着UI必须等待(这在
async
操作中无法发生),因此属性不能设置为
async
,因此不能使用
wait

我现在使用的所有解决办法是什么:

  • 异步任务返回方法有一个属性,名为
    .Result
    。我已经试过了,它并没有提供最好的输出
  • 您可以使您的方法返回一个
    IAsyncOperation
    ,而不是
    Task
    。这将为您提供调用
    .GetResults()
    方法的优势,该方法将获得结果,并且不会冻结UI线程。更多关于它的信息。如果没有要执行的任何后期结果获取操作,请使用此选项
  • 最后,这个选项是我最常用的一个,我创建了一个异步方法,返回
    Task
    。我在那里执行所有操作并验证结果。一旦得到所需的结果,我只需更新属性并调用
    RaisePropertyChanged
    。这样,我也可以处理其他视图处理或中间加载屏幕,而不必受到无法停止处理线程的限制
    底线 使用我在上面定义的三种方法之一。他们都很好。下面是用例的总结点,以从游戏服务器获取分数为例:

  • 如果您不想停止任何线程,只想定义属性的数据源,请使用
    IAsyncOperation
    。代码处理不会停止或等待进程获得结果。你只要把分数拿出来并显示出来就行了
  • 如果希望代码等待任务完成后再对结果执行其他操作,请使用
    Task
    returning方法。计算分数后,您希望将整数值转换为百分比
  • 使用
    .Result
    ,但它从未对我起过作用 如果还有什么,请随时在评论中提及

    包含对我要使其异步的方法的调用

    我有一篇关于你的文章。本质上,我通常做的是创建一个可绑定的
    任务
    ——我在文章中称之为
    NotifyTaskCompletion
    ,简称为

    您可以通过将
    StaffHolidaysViewModel.HolidayAllowance
    的类型从任何类型(我将其称为
    THolidayAllowance
    )更改为
    NotifyTask
    包装器(例如,
    NotifyTask
    )来使用它

    然后,您可以同步设置它:

    StaffHolidaysViewModel.HolidayAllowance = NotifyTask.Create(
        _staffDataService.EmployeeHolidayAllowanceAsync(_selectedEmployee.Id));
    
    您在这里要做的是启动
    EmployeeHolidayAllowanceSync
    ,然后用
    NotifyTask
    包装其
    任务。这是同步完成的,因此可以在属性设置器中完成


    然后,还需要更新数据绑定。最明显的是
    Result
    ,它最终将保存
    EmployeeHolidayaAllowanceAsync
    的结果(在
    EmployeeHolidayaAllowanceAsync
    完成之前,它将返回一个默认值)。还有
    IsNotCompleted
    IsFaulted
    ,您希望使用它们向用户指示数据尚未到达或存在错误。

    我的理解是这是不可能的。绑定机制要求属性在该时刻直接返回值。不过,有一些可用的模式可以间接地处理它。请参阅Stephen Cleary的MSDN帖子: