Search code examples
c#mvvmasync-ctpxunit.net

using dependency properties along with async ctp


I have created some sample ViewModel to test usage of DPs with 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;
    }
}

and the model which injected to ViewModel is:

public interface ISampleModel
{
    int GetSomeIntegerValue();
}

public class SampleModel : ISampleModel
{
    public int GetSomeIntegerValue()
    {
        return 10;
    }
}

when I run the WPF application there is no problem, but when I want to test it with the following code:

[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);
}

I got the following error:

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 

so what is the solution?


Solution

  • First, I recommend that you upgrade to VS2012 with the Microsoft.Bcl.Async package. This will enable you to target .NET 4.0 with the newest tools. The Async CTP has known bugs that will not be fixed, and it has installation issues (that won't be fixed) that will make setting up new development machines quite difficult.

    But before you delete the Async CTP, check out your (C# Testing) Unit Testing directory under the Async CTP directory. You'll find several types to help with unit testing, such as 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);
    }