将可移植类库与模型-视图-视图模型配合使用Using Portable Class Library with Model-View-View Model

可以使用.NET Framework可移植类库实现模型-视图-视图模型 (MVVM) 模式并跨多个平台共享程序集。You can use the .NET Framework Portable Class Library to implement the Model-View-View Model (MVVM) pattern and share assemblies across multiple platforms.

重要

因为可移植类库项目面向的.NET 实现仅非常特定的专项,我们强烈建议不要在新的应用程序开发中使用它们。Because Portable Class Library projects target only a very specific subset of .NET implementations, we strongly discourage their use in new application development. 推荐的替代是面向所有支持特定版本的.NET Standard 的.NET 实现的.NET Standard 库。The recommended replacement is a .NET Standard library, which targets all .NET implementations that support a specific version of the .NET Standard. 有关详细信息,请参阅 .NET StandardFor more information, see .NET Standard.

MVVM 是将用户界面与基础业务逻辑相隔离的应用程序模式。MVVM is an application pattern that isolates the user interface from the underlying business logic. 您可以在 Visual Studio 2012 中,可移植类库项目中实现模型和视图模型类,然后创建针对不同平台自定义的视图。You can implement the model and view model classes in a Portable Class Library project in Visual Studio 2012, and then create views that are customized for different platforms. 通过此方法,只需编写数据模型和业务逻辑一次,即可将该代码用于 .NET Framework、Silverlight、Windows Phone 和 Windows 8.x 应用商店Windows 8.x Store 应用,如下图所示。This approach enables you to write the data model and business logic only once, and use that code from .NET Framework, Silverlight, Windows Phone, and Windows 8.x 应用商店Windows 8.x Store apps, as shown in the following illustration.

显示跨平台可移植类库与 MVVM 共享程序集。

本主题不提供有关 MVVM 模式的一般信息。This topic does not provide general information about the MVVM pattern. 它仅提供有关如何使用可移植类库实现 MVVM 的信息。It only provides information about how to use Portable Class Library to implement MVVM. 有关 MVVM 的详细信息,请参阅MVVM 快速入门使用 Prism Library 5.0 的 WPFFor more information about MVVM, see the MVVM Quickstart Using the Prism Library 5.0 for WPF.

支持 MVVM 类Classes That Support MVVM

在面向.NET Framework 4.5 时适用于 Windows 8.x 应用商店应用的 .NET.NET for Windows 8.x Store apps,Silverlight 或 Windows Phone 7.5 可移植类库项目,下列类是可用于实现 MVVM 模式:When you target the .NET Framework 4.5, 适用于 Windows 8.x 应用商店应用的 .NET.NET for Windows 8.x Store apps, Silverlight, or Windows Phone 7.5 for your Portable Class Library project, the following classes are available for implementing the MVVM pattern:

实现 MVVMImplementing MVVM

若要实现 MVVM,您通常创建模型和视图模型在可移植类库项目中,因为可移植类库项目不能引用不可移植的项目。To implement MVVM, you typically create both the model and the view model in a Portable Class Library project, because a Portable Class Library project cannot reference a non-portable project. 模型和视图模型可以是同一个项目中或单独的项目中。The model and view model can be in the same project or in separate projects. 如果使用单独的项目,添加从视图模型项目到模型项目的引用。If you use separate projects, add a reference from the view model project to the model project.

编译模型并查看模型项目后,您引用的包含视图的应用中的这些程序集。After you compile the model and view model projects, you reference those assemblies in the app that contains the view. 如果该视图仅与视图模型进行交互,只需引用包含视图模型的程序集。If the view interacts only with the view model, you only have to reference the assembly that contains the view model.

模型Model

下面的示例演示可以驻留在可移植类库项目中的简化的模型类。The following example shows a simplified model class that could reside in a Portable Class Library project.

using System;

namespace SimpleMVVM.Model
{  
    public class Customer
    {
        public int CustomerID
        {
            get; 
            set;   
        }

        public string FullName
        {
            get;
            set;
        }

        public string Phone
        {
            get; 
            set;
        }
    }
}
Namespace SimpleMVVM.Model

    Public Class Customer
        Public Property CustomerID() As Integer
        Public Property FullName() As String
        Public Property Phone() As String
    End Class
End Namespace

下面的示例介绍了简单的方法以填充、 检索和更新可移植类库项目中的数据。The following example shows a simple way to populate, retrieve, and update the data in a Portable Class Library project. 在实际应用中,将从 Windows Communication Foundation (WCF) 服务等源检索数据。In a real app, you would retrieve the data from a source such as a Windows Communication Foundation (WCF) service.

using System;
using System.Collections.Generic;
using System.Linq;

namespace SimpleMVVM.Model
{
    public class CustomerRepository
    {
        private List<Customer> _customers;

        public CustomerRepository()
        {
            _customers = new List<Customer>
            {
                new Customer(){ CustomerID = 1, FullName="Dana Birkby", Phone="394-555-0181"},
                new Customer(){ CustomerID = 2, FullName="Adriana Giorgi", Phone="117-555-0119"},
                new Customer(){ CustomerID = 3, FullName="Wei Yu", Phone="798-555-0118"}
            };
        }

        public List<Customer> GetCustomers()
        {
            return _customers;
        }

        public void UpdateCustomer(Customer SelectedCustomer)
        {
            Customer customerToChange = _customers.Single(c => c.CustomerID == SelectedCustomer.CustomerID);
            customerToChange = SelectedCustomer;
        }
    }
}
Namespace SimpleMVVM.Model
    Public Class CustomerRepository
        Private _customers As List(Of Customer)

        Public Sub New()
            _customers = New List(Of Customer) From
            {
                New Customer() With {.CustomerID = 1, .FullName = "Dana Birkby", .Phone = "394-555-0181"},
                New Customer() With {.CustomerID = 2, .FullName = "Adriana Giorgi", .Phone = "117-555-0119"},
                New Customer() With {.CustomerID = 3, .FullName = "Wei Yu", .Phone = "798-555-0118"}
            }
        End Sub

        Public Function GetCustomers() As List(Of Customer)
            Return _customers
        End Function

        Public Sub UpdateCustomer(SelectedCustomer As Customer)
            Dim customerToChange = _customers.Single(Function(c) c.CustomerID = SelectedCustomer.CustomerID)
            customerToChange = SelectedCustomer
        End Sub
    End Class
End Namespace

视图模型View Model

在实现 MVVM 模式时,经常添加的视图模型的基类。A base class for view models is frequently added when implementing the MVVM pattern. 下面的示例显示了一个基类。The following example shows a base class.

using System;
using System.ComponentModel;

namespace SimpleMVVM.ViewModel
{
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
}
Imports System.ComponentModel

Namespace SimpleMVVM.ViewModel

    Public MustInherit Class ViewModelBase
        Implements INotifyPropertyChanged

        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

        Protected Overridable Sub OnPropertyChanged(propname As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propname))
        End Sub
    End Class
End Namespace

实现ICommand接口经常采用 MVVM 模式。An implementation of the ICommand interface is frequently used with the MVVM pattern. 下面的示例演示 ICommand 接口的实现。The following example shows an implementation of the ICommand interface.

using System;
using System.Windows.Input;

namespace SimpleMVVM.ViewModel
{
    public class RelayCommand : ICommand
    {
        private readonly Action _handler;
        private bool _isEnabled;

        public RelayCommand(Action handler)
        {
            _handler = handler;
        }

        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                if (value != _isEnabled)
                {
                    _isEnabled = value;
                    if (CanExecuteChanged != null)
                    {
                        CanExecuteChanged(this, EventArgs.Empty);
                    }
                }
            }
        }

        public bool CanExecute(object parameter)
        {
            return IsEnabled;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            _handler();
        }
    }
}
Imports System.Windows.Input

Namespace SimpleMVVM.ViewModel

    Public Class RelayCommand
        Implements ICommand

        Private _isEnabled As Boolean
        Private ReadOnly _handler As Action

        Public Sub New(ByVal handler As Action)
            _handler = handler
        End Sub

        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

        Public Property IsEnabled() As Boolean
            Get
                Return _isEnabled
            End Get
            Set(ByVal value As Boolean)
                If (value <> _isEnabled) Then
                    _isEnabled = value
                    RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
                End If
            End Set
        End Property

        Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            Return IsEnabled
        End Function

        Public Sub Execute(parameter As Object) Implements ICommand.Execute
            _handler()
        End Sub

    End Class
End Namespace

下面的示例显示了一个简化的视图模型。The following example shows a simplified view model.

using System;
using System.Collections.Generic;
using SimpleMVVM.Model;

namespace SimpleMVVM.ViewModel
{
    public class CustomerViewModel : ViewModelBase
    {
        private List<Customer> _customers;
        private Customer _currentCustomer;
        private CustomerRepository _repository;

        public CustomerViewModel()
        {
            _repository = new CustomerRepository();
            _customers = _repository.GetCustomers();

            WireCommands();
        }

        private void WireCommands()
        {
            UpdateCustomerCommand = new RelayCommand(UpdateCustomer);
        }

        public RelayCommand UpdateCustomerCommand
        {
            get;
            private set;
        }

        public List<Customer> Customers
        {
            get { return _customers; }
            set { _customers = value; }
        }

        public Customer CurrentCustomer
        {
            get
            {
                return _currentCustomer;
            }

            set
            {
                if (_currentCustomer != value)
                {
                    _currentCustomer = value;
                    OnPropertyChanged("CurrentCustomer");
                    UpdateCustomerCommand.IsEnabled = true;
                }
            }
        }

        public void UpdateCustomer()
        {
            _repository.UpdateCustomer(CurrentCustomer);
        }
    }
}
Imports System.Collections.Generic
Imports SimpleMVVM.Model

Namespace SimpleMVVM.ViewModel

    Public Class CustomerViewModel
        Inherits ViewModelBase

        Private _customers As List(Of Customer)
        Private _currentCustomer As Customer
        Private _repository As CustomerRepository
        Private _updateCustomerCommand As RelayCommand

        Public Sub New()
            _repository = New CustomerRepository()
            _customers = _repository.GetCustomers()

            WireCommands()
        End Sub

        Private Sub WireCommands()
            UpdateCustomerCommand = New RelayCommand(AddressOf UpdateCustomer)
        End Sub

        Public Property UpdateCustomerCommand() As RelayCommand
            Get
                Return _updateCustomerCommand
            End Get
            Private Set(value As RelayCommand)
                _updateCustomerCommand = value
            End Set
        End Property

        Public Property Customers() As List(Of Customer)
            Get
                Return _customers
            End Get
            Set(value As List(Of Customer))
                _customers = value
            End Set
        End Property

        Public Property CurrentCustomer() As Customer
            Get
                Return _currentCustomer
            End Get
            Set(value As Customer)
                If _currentCustomer.Equals(value) Then
                    _currentCustomer = value
                    OnPropertyChanged("CurrentCustomer")
                    UpdateCustomerCommand.IsEnabled = True
                End If
            End Set
        End Property

        Public Sub UpdateCustomer()
            _repository.UpdateCustomer(CurrentCustomer)
        End Sub
    End Class
End Namespace

视图View

从.NET Framework 4.5 应用程序,Windows 8.x 应用商店Windows 8.x Store应用、 基于 Silverlight 的应用或 Windows Phone 7.5 应用程序,可以引用包含模型和视图模型项目的程序集。From a .NET Framework 4.5 app, Windows 8.x 应用商店Windows 8.x Store app, Silverlight-based app, or Windows Phone 7.5 app, you can reference the assembly that contains the model and view model projects. 您然后创建视图模型进行交互的视图。You then create a view that interacts with the view model. 下面的示例演示一个简化的 Windows Presentation Foundation (WPF) 应用检索和更新视图模型中的数据。The following example shows a simplified Windows Presentation Foundation (WPF) app that retrieves and updates data from the view model. 可以在 Silverlight 中,Windows Phone 创建类似的视图或Windows 8.x 应用商店Windows 8.x Store应用。You could create similar views in Silverlight, Windows Phone, or Windows 8.x 应用商店Windows 8.x Store apps.

<Window x:Class="SimpleWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModels="clr-namespace:SimpleMVVM.ViewModel;assembly=SimpleMVVM.ViewModel"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <viewModels:MainPageViewModel x:Key="ViewModel" />
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource ViewModel}}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Height="23" Margin="5" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="0" Name="textBlock2" 
                   Text="Select a Customer:" VerticalAlignment="Top" />
        <ComboBox Height="23" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="0" Name="CustomersComboBox" VerticalAlignment="Top" Width="173" 
                  DisplayMemberPath="FullName" SelectedItem="{Binding Path=CurrentCustomer, Mode=TwoWay}" ItemsSource="{Binding Path=Customers}" />
        <TextBlock Height="23" Margin="5" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="1" Name="textBlock4" Text="Customer ID" />
        <TextBlock Height="23" Margin="5" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="2" Name="textBlock5" Text="Name" />
        <TextBlock Height="23" Margin="5" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="3" Name="textBlock9" Text="Phone" />
        <TextBlock Height="23" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="1" Name="CustomerIDTextBlock" 
                   Text="{Binding ElementName=CustomersComboBox, Path=SelectedItem.CustomerID}" />
        <TextBox Height="23" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="2" Width="219" 
                 Text="{Binding Path=CurrentCustomer.FullName, Mode=TwoWay}" />
        <TextBox Height="23" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="3" Width="219" 
                 Text="{Binding Path=CurrentCustomer.Phone, Mode=TwoWay}" />
        <Button
            Command="{Binding UpdateCustomerCommand}"
            Content="Update" Height="23" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="4" 
            Name="UpdateButton" VerticalAlignment="Top" Width="75" />
    </Grid>
</Window>

请参阅See also