C# 将依赖项属性与异步ctp一起使用

C# 将依赖项属性与异步ctp一起使用,c#,mvvm,async-ctp,xunit.net,C#,Mvvm,Async Ctp,Xunit.net,我创建了一些示例ViewModel来测试DPs与asyncCtp的使用情况: public class SampleVm : DependencyObject { public static readonly DependencyProperty SampleDependencyPropertyProperty = DependencyProperty.Register("SampleDependencyProperty", typeof (int), typeof (

我创建了一些示例ViewModel来测试DPs与asyncCtp的使用情况:

public class SampleVm : DependencyObject
{

    public static readonly DependencyProperty SampleDependencyPropertyProperty =
        DependencyProperty.Register("SampleDependencyProperty", typeof (int), typeof (SampleVm), new PropertyMetadata(default(int)));

    public int SampleDependencyProperty
    {
        get { return (int) GetValue(SampleDependencyPropertyProperty); }
        set { SetValue(SampleDependencyPropertyProperty, value); }
    }
    public ISampleModel _model;
    public SampleVm(ISampleModel model)
    {
        _model = model;
    }

    public async Task SetDependencyProperty()
    {
        var modelData = await TaskEx.Run(() => _model.GetSomeIntegerValue());
        SampleDependencyProperty = modelData;
    }
}
注入ViewModel的模型为:

public interface ISampleModel
{
    int GetSomeIntegerValue();
}

public class SampleModel : ISampleModel
{
    public int GetSomeIntegerValue()
    {
        return 10;
    }
}
当我运行WPF应用程序时没有问题,但是当我想用以下代码测试它时:

[Fact]
public async Task CheckValueSetting()
{
    var model = new Mock<ISampleModel>();
    model.Setup(x => x.GetSomeIntegerValue()).Returns(5);
    var viewModel =new SampleVm(model.Object);

    await viewModel.SetDependencyProperty();

    Assert.Equal(5, viewModel.SampleDependencyProperty);
}
[事实]
公共异步任务CheckValueSetting()
{
var模型=新的Mock();
Setup(x=>x.GetSomeIntegerValue())。返回(5);
var viewModel=newsamplevm(model.Object);
等待viewModel.SetDependencyProperty();
Assert.Equal(5,viewModel.SampleDependencyProperty);
}
我得到了以下错误:

System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.

Server stack trace: 

    at System.Windows.Threading.Dispatcher.VerifyAccess()
    at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
    at WpfApplication4.SampleVm.set_SampleDependencyProperty(Int32 value) in SampleVM.cs: line 19
    at WpfApplication4.SampleVm.<SetDependencyProperty>d__1.MoveNext() in SampleVM.cs: line 30

    Exception rethrown at [0]: 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    at WpfApplication4.SampleVmFixture.<CheckValueSetting>d__0.MoveNext() in SampleVmFixture.cs: line 16 
System.InvalidOperationException:调用线程无法访问此对象,因为另一个线程拥有它。
服务器堆栈跟踪:
在System.Windows.Threading.Dispatcher.VerifyAccess()中
位于System.Windows.DependencyObject.SetValue(DependencyProperty dp,对象值)
在WpfApplication4.SampleVm.set_SampleDependencyProperty(Int32值)中的SampleVm.cs:第19行
在SampleVm.cs中的WpfApplication4.SampleVm.d_u1.MoveNext()处:第30行
在[0]处重试异常:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskAwaiter.GetResult()中
在SampleVmFixture.cs中的WpfApplication4.SampleVmFixture.d_u0.MoveNext()处:第16行

那么解决方案是什么呢?

首先,我建议您使用升级到VS2012。这将使您能够使用最新的工具以.NET4.0为目标。Async CTP已知无法修复的bug,并且它存在安装问题(无法修复),这将使设置新的开发机器变得非常困难

但在删除异步CTP之前,请查看异步CTP目录下的
(C#Testing)单元测试
目录。您可以找到几种类型来帮助进行单元测试,例如
GeneralThreadAffineContext

[Fact]
public async Task CheckValueSetting()
{
    var model = new Mock<ISampleModel>();
    model.Setup(x => x.GetSomeIntegerValue()).Returns(5);
    SampleVm viewModel;
    await GeneralThreadAffineContext.Run(async () =>
    {
        viewModel = new SampleVm(model.Object);
        await viewModel.SetDependencyProperty();
    });

    Assert.Equal(5, viewModel.SampleDependencyProperty);
}
[事实]
公共异步任务CheckValueSetting()
{
var模型=新的Mock();
Setup(x=>x.GetSomeIntegerValue())。返回(5);
SampleVm视图模型;
等待GeneralThreadAffineContext.Run(异步()=>
{
viewModel=新的SampleVm(model.Object);
等待viewModel.SetDependencyProperty();
});
Assert.Equal(5,viewModel.SampleDependencyProperty);
}

我可以检查一下:为什么您仍在使用异步CTP?这不都在core.NET中吗?由于公司的限制,我不得不使用.NETFramework4。这完全没有意义。根据定义,CTP是完全不受支持的,在这种情况下,CTP现在已经过时。在任何情况下,使用CTP都比面对升级更好。IMO:升级(即使这意味着一些内部工作),或者忘记异步。最后:大部分异步内容都在4.0中!!!以.NET4为目标是有意义的,特别是因为“就地”4.5升级不支持XP。他可能只是不知道Microsoft.Bcl.Async。感谢@MarcGravel和StephenCleary的建议。在阅读了这篇文章和这篇文章之后,我认为解决方案不是继续使用AsyncCtp。CTP中的示例在其他地方不可用?另外,我认为您忘记了等待
运行()的结果<我的AsyncEx库中的code>AsyncContext
GeneralThreadAffineContext
非常接近,但我不知道有什么东西与
WindowsFormsContext
WpfContext
等效。另外,
Run
返回
void
(在所有
async
方法完成之前,它不会完成。)
GeneralThreadAffineContext
我有几个
Run()
的重载:
void Run(Action asyncAction)
Task Run(Func asyncMethod)
,因为您正在使用第二个,我认为你必须等待它。@svick:你是对的;我修改了我的副本。从技术上讲,
Run
重载将等待
async
方法完成,但等待它并没有什么害处。