Silverlight 构造函数注入视图模型 +设计模式

发布于 2024-09-29 17:49:04 字数 885 浏览 3 评论 0原文

我正在尝试在 Silverlight 4 中编写可测试的 ViewModel。我目前使用 MVVM light。

我使用 AutoFac,IoCContainer 做得很好。然而,要注入 ViewModels 的构造函数(它绑定到 Views),我有这个构造函数链:

    public UserViewModel() : this(IoCContainer.Resolve<IUserServiceAsync>())
    {

    }

    public UserViewModel(IUserServiceAsync userService) 
    {
        if (this.IsInDesignMode) return;

        _userService = userService;
    }

感觉不太干净,但这是我迄今为止找到的最佳选择。这有效,我的应用程序按预期工作,并且可以通过控制反转进行测试。

但是,当我的 VM 绑定到我的视图时,如下所示:

 <UserControl.DataContext>
            <ViewModel:UserViewModel />
 </UserControl.DataContext>

在我的 XAML 页面属性中,VS2010 和 Blend 中的设计模式都不起作用。

有没有更好的方法来实现我在 Silverlight 中尝试的仍然适用于设计模式的功能?失去设计模式并不影响交易,但在学习 XAML 时会很方便。不过,更干净的非连锁方式会很好!

我认为也许可以使用 AutoFac / IoC 将视图模型解析为视图,与上面的 XAML 标记方法相反,并沿着这条路线走下去?

谢谢。

Im trying to get to grips with writing testable ViewModels in Silverlight 4. Im currently using MVVM light.

Im using AutoFac and the IoCContainer is doing its job fine. However to inject into the constructor of ViewModels, which are bound to Views I have this constructor chaining:

    public UserViewModel() : this(IoCContainer.Resolve<IUserServiceAsync>())
    {

    }

    public UserViewModel(IUserServiceAsync userService) 
    {
        if (this.IsInDesignMode) return;

        _userService = userService;
    }

Which doesn't feel clean, but is the best option i have found so far. This works and my app works as desired, and is testable with control inverted.

However, with my VM bound to my view like this:

 <UserControl.DataContext>
            <ViewModel:UserViewModel />
 </UserControl.DataContext>

In my XAML page attributes, design mode in both VS2010 and Blend doesnt work.

Is there are nicer way to achieve what im trying in Silverlight that still works with design mode? Losing design mode isnt a deal breaker but will be handy while learning XAML. A cleaner none chained way would be nice though!

Im thinking it maybe possible to use AutoFac / IoC to resolve viewmodels to views, as apposed to the XAML mark-up approach above, and go down this route?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

遮了一弯 2024-10-06 17:49:04

我建议您实现一个 ViewModelLocator,而不是实现第一个构造函数,如下所示:

public class ViewModelLocator
{

    IoCContainer Container { get; set; }

    public IUserViewModel UserViewModel
    {
        get
        {
            return IoCContainer.Resolve<IUserViewModel>();
        }
    }

}

然后在 XAML 中将定位器声明为静态资源:

<local:ViewModelLocator x:Key="ViewModelLocator"/>

在初始化应用程序时,有必要为定位器提供容器的实例:

var viewModelLocator = Application.Current.Resources["ViewModelLocator"] as ViewModelLocator;
if(viewModelLocator == null) { // throw exception here }
viewModelLocator.Container = IoCContainer;

然后在 XAML 中,您可以干净地使用资源:

<UserControl
    DataContext="{Binding Path=UserViewModel, Source={StaticResource ViewModelLocator}}"
    />
    <!-- The other user control properties -->

在设计时,您可以实现 MockViewModelLocator:

public class MockViewModelLocator
{

    public IUserViewModel UserViewModel
    {
        get
        {
            return new MockUserViewModel();
        }
    }

}

在 XAML 中适当地声明它:

<local:MockViewModelLocator x:Key="MockViewModelLocator"/>

最后在用户控件中使用它:

<UserControl
    d:DataContext="{Binding Path=UserViewModel, Source={StaticResource MockViewModelLocator}}"
    DataContext="{Binding Path=UserViewModel, Source={StaticResource ViewModelLocator}}"
    />
    <!-- The other user control properties -->

您可以使模拟视图模型定位器为 Blend 返回安全且易于读取的数据使用并且在运行时您将使用真正的服务。

这样,您就不会丢失设计时数据,也不必牺牲视图模型中依赖项注入方法的简洁性。

我希望这有帮助。

Instead of implementing the first constructor, I suggest you implement a ViewModelLocator, like this:

public class ViewModelLocator
{

    IoCContainer Container { get; set; }

    public IUserViewModel UserViewModel
    {
        get
        {
            return IoCContainer.Resolve<IUserViewModel>();
        }
    }

}

Then in XAML you declare the locator as a static resource:

<local:ViewModelLocator x:Key="ViewModelLocator"/>

While you initialize your application, it is necessary to provide the locator with the instance of the container:

var viewModelLocator = Application.Current.Resources["ViewModelLocator"] as ViewModelLocator;
if(viewModelLocator == null) { // throw exception here }
viewModelLocator.Container = IoCContainer;

Then in XAML you can use the resource cleanly:

<UserControl
    DataContext="{Binding Path=UserViewModel, Source={StaticResource ViewModelLocator}}"
    />
    <!-- The other user control properties -->

For design time, you can implement a MockViewModelLocator:

public class MockViewModelLocator
{

    public IUserViewModel UserViewModel
    {
        get
        {
            return new MockUserViewModel();
        }
    }

}

Declare it in XAML appropriately:

<local:MockViewModelLocator x:Key="MockViewModelLocator"/>

And finally use it in your user control:

<UserControl
    d:DataContext="{Binding Path=UserViewModel, Source={StaticResource MockViewModelLocator}}"
    DataContext="{Binding Path=UserViewModel, Source={StaticResource ViewModelLocator}}"
    />
    <!-- The other user control properties -->

You can make your mock view model locator return safe and easily readable data for Blend to use and during runtime you will be using your real service.

This way you do not lose design time data and you do not have to sacrifice the cleanliness of the dependency injection methodology in your view models.

I hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文