我有一套现有的Silverlight应用程序,使用MVVM模式将Views和ViewModels分开。我们将Unity 2.0用于IoC容器,以将依赖项注入(inject)ViewModel类(和支持类型)中。我有一个现有的ViewModelLocator类,该类使用Unity容器解析ViewModel。

所有这些在运行时都很好。但是,由于ViewModelLocator依赖于由Bootstrapper类创建和配置的Unity容器,该类是从App.xaml.cs中的Application_Start方法“运行”的,因此我失去了在设计器或Blend中打开 View 的能力。

我正在寻找有关如何重新设计ViewModelLocator以支持“可混合性”的建议。

请注意,我不愿意为了混合性而强制我们的ViewModel类实现默认的无参数构造函数。我们还让ViewModels检查IsInDesignMode属性(来自MVVM Light ViewModelBase类)来提供设计时数据与进行服务调用,因此我们在设计时和运行时没有不同的ViewModel实现。

让我知道你的想法。

最佳答案

您希望UI元素具有良好的设计时体验(包括Blend中的体验)。这听起来像是一个合理的目标。

让我们看一下UI元素是什么。对于此答案的其余部分,我将其称为“控件”。控件的职责是呈现UI并响应用户事件。就其应具有的行为而言,它应仅具有与UI呈现和用户事件有关的行为。

除此之外,框架本身(Silverlight和WPF)还强加了一条规则:所有控件都必须具有默认构造函数。此外,由于DataContext是属性,因此可以选择分配它。

我们应该牢记封装。我们开发的任何控件都应在上述限制内正常运行。这意味着,除了拥有默认的构造函数之外,它的在没有DataContext 的情况下也应该可以正常工作。换句话说,可混合性体验应由控件本身提供,而不是需要引导以分配DataContext的任何外部容器。

当控件必须响应用户事件时,我总是发现ICommand接口(interface)绰绰有余。将ICommands附加到控件中任何适用的事件处理程序。 ICommands由 View 模型定义,但是ICommand的优点在于,它基本上是一个void方法,这意味着在DataContext为null的情况下,提供(无操作)本地默认值很简单。但是,这几乎没有必要,因为设计人员不会调用命令。

这是my book的示例:

<Window x:Class="Ploeh.Samples.ProductManagement.WpfClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Product Management"
        Height="300"
        Width="300"
        MinHeight="300"
        MinWidth="300">
    <Window.Resources>
        <Style x:Key="ProductStyle" TargetType="{x:Type ListViewItem}">
            <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
        </Style>
    </Window.Resources>
    <DockPanel FocusManager.FocusedElement="{Binding ElementName=productsListView}">
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_File">
                <Separator />
                <MenuItem Header="E_xit" Command="{Binding Path=CloseCommand}" />
            </MenuItem>
            <MenuItem Header="_Actions">
                <MenuItem Header="_Refresh" InputGestureText="F5" Command="{Binding Path=RefreshCommand}" />
                <MenuItem Header="_Add Product" InputGestureText="Ins" Command="{Binding Path=InsertProductCommand}" />
                <MenuItem Header="_Edit Product" InputGestureText="Enter" Command="{Binding Path=EditProductCommand}" />
                <MenuItem Header="_Delete Product" InputGestureText="Del" Command="{Binding Path=DeleteProductCommand}" />
            </MenuItem>
        </Menu>
        <ToolBarTray DockPanel.Dock="Top" HorizontalAlignment="Stretch">
            <ToolBar HorizontalAlignment="Stretch" HorizontalContentAlignment="Left">
                <Button Command="{Binding Path=RefreshCommand}">Refresh</Button>
                <Button Command="{Binding Path=InsertProductCommand}">Add</Button>
                <Button Command="{Binding Path=EditProductCommand}">Edit</Button>
                <Button Command="{Binding Path=DeleteProductCommand}">Delete</Button>
            </ToolBar>
        </ToolBarTray>
        <ListView x:Name="productsListView" ItemContainerStyle="{StaticResource ProductStyle}" ItemsSource="{Binding Path=Products}" SelectionMode="Single">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Id" DisplayMemberBinding="{Binding Path=Id}" />
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" />
                    <GridViewColumn Header="Price" DisplayMemberBinding="{Binding Path=UnitPrice}" />
                </GridView>
            </ListView.View>
        </ListView>
    </DockPanel>
</Window>

和背后的代码:
public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
    }
}

关于mvvm - 关于Unity 2.0的 “Blendable” ViewModelLocator的建议,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7264419/

10-11 03:59