• DevExpress WPF入门指南 运行时生成的POCO视图模型(三)


    POCO(Plain Old CLR Objects)视图模型简化并加快了开发过程。

    POCO 视图模型允许您:

    • 将可绑定属性定义为简单的自动实现的属性。
    • 创建在运行时用作命令的方法。
    • 使属性和方法实现特定于 MVVM 的接口。

    这允许您创建干净、简单、可维护和可测试的 MVVM 代码,POCO 视图模型与任何 WPF 控件完全兼容。

    您可以使用在编译时生成的视图模型在编译时为您的视图模型生成样板代码。

    DevExpress WPF v21.2正式版下载

    Services

    DevExpress MVVM框架包括Services机制,下面的代码示例演示了如何访问 Message Box 服务。

    C#

    using DevExpress.Mvvm.POCO;
    ...
    public class LoginViewModel {
    public IMessageBoxService MessageBoxService { get { return this.GetService<IMessageBoxService>(); } }
    }
    依赖注入

    要将视图绑定到视图模型,请创建解析正确 ViewModel 类型的 MarkupExtension:

    C#

    public class DISource : MarkupExtension {
    public static Func<Type, object, string, object> Resolver { get; set; }
    
    public Type Type { get; set; }
    public object Key { get; set; }
    public string Name { get; set; }
    
    public override object ProvideValue(IServiceProvider serviceProvider) => Resolver?.Invoke(Type, Key, Name);
    }

    在应用程序启动时注册解析器:

    C#

    protected override void OnStartup(StartupEventArgs e) {
    base.OnStartup(e);
    DISource.Resolver = Resolve;
    }
    object Resolve(Type type, object key, string name) {
    if(type == null)
    return null;
    if(key != null)
    return Container.ResolveKeyed(key, type);
    if(name != null)
    return Container.ResolveNamed(name, type);
    return Container.Resolve(type);
    }

    通过以下方式在 XAML 中指定 DataContext:

    XAML

    DataContext="{common:DISource Type=common:MainViewModel}"

    要在依赖注入容器中使用 POCO 视图模型,请利用 ViewModelSource.GetPOCOType 方法注册在运行时生成的 POCO 类型:

    C#

    container.RegisterType(typeof(IMainViewModel),
    ViewModelSource.GetPOCOType(typeof(MainViewModel)));
    查看模型父子关系

    POCO 视图模型可以通过父子关系相互关联。 这是通过 ISupportParentViewModel 接口实现的,该接口在您使用 ViewModelSource 类创建 POCO 对象时自动实现。 通过这个接口,子视图模型可以访问在主视图模型中注册的服务。

    自动 IDataErrorInfo 实现

    IDataErrorInfo 接口是 WPF 中数据验证的标准机制,您可以使用此接口为每个单独的属性或整个对象定义验证规则。 POCO 机制允许您基于定义的属性或 Fluent API 自动实现IDataErrorInfo 接口。

    要启用此功能,请为您的视图模型应用 POCOViewModel 属性并将 POCOViewModel.ImplementIDataErrorInfo 参数设置为 True。

    C#

    //Attribute-based approach
    [POCOViewModel(ImplementIDataErrorInfo = true)]
    public class LoginViewModel {
    [Required(ErrorMessage = "Please enter the user name.")]
    public virtual string UserName { get; set; }
    }
    
    //Fluent API
    [POCOViewModel(ImplementIDataErrorInfo = true)]
    [MetadataType(typeof(LoginViewModel.Metadata))]
    public class LoginViewModel {
    public class Metadata : IMetadataProvider<LoginViewModel> {
    void IMetadataProvider<LoginViewModel>.BuildMetadata(MetadataBuilder<LoginViewModel> builder) {
    builder.Property(x => x.UserName).
    Required(() => "Please enter the user name.");
    }
    }
    public virtual string UserName { get; set; }
    }

    当 ViewModelSource 生成 View Model 的后代时,它会实现 IDataErrorInfo 接口,如下所示:

    C#

    public class LoginViewModel : IDataErrorInfo {
    ...
    string IDataErrorInfo.Error {
    get { return string.Empty; }
    }
    string IDataErrorInfo.this[string columnName] {
    get { return IDataErrorInfoHelper.GetErrorText(this, columnName); }
    }
    }

    IDataErrorInfoHelper类允许您根据指定的DataAnnotation 属性或 Fluent API 获取错误。

    下面的代码示例演示了如何使用 POCO 机制来实现 IDataErrorInfo 接口。

    MainView.xaml

    <UserControl x:Class="Example.View.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
    xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
    xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
    xmlns:ViewModel="clr-namespace:Example.ViewModel"
    mc:Ignorable="d" d:DesignHeight="400" d:DesignWidth="400"
    DataContext="{dxmvvm:ViewModelSource Type=ViewModel:MainViewModel}">
    <UserControl.Resources>
    <dxmvvm:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
    </UserControl.Resources>
    
    <Grid>
    <StackPanel Orientation="Vertical" Margin="10" dxe:ValidationService.IsValidationContainer="True" x:Name="validationContainer">
    <Grid>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <StackPanel Orientation="Vertical" Margin="0,0,4,6">
    <TextBlock Text="Name" Margin="6,2,0,2"/>
    <dxe:TextEdit NullText="First" EditValue="{Binding FirstName, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
    <StackPanel Orientation="Vertical" Margin="4,0,0,6" Grid.Column="1">
    <TextBlock Text=" " Margin="6,2,0,2"/>
    <dxe:TextEdit NullText="Last" EditValue="{Binding LastName, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
    </Grid>
    <StackPanel Orientation="Vertical" Margin="0,0,0,6">
    <TextBlock Text="Email" Margin="6,2,0,2"/>
    <dxe:TextEdit EditValue="{Binding Email, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
    <StackPanel Orientation="Vertical" Margin="0,0,0,6">
    <TextBlock Text="Password" Margin="6,2,0,2"/>
    <dxe:PasswordBoxEdit EditValue="{Binding Password, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
    <StackPanel Orientation="Vertical" Margin="0,0,0,6">
    <TextBlock Text="Confirm Password" Margin="6,2,0,2"/>
    <dxe:PasswordBoxEdit EditValue="{Binding ConfirmPassword, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
    
    <Button VerticalAlignment="Top" Content="Sign Up" Width="150" HorizontalAlignment="Right" Margin="0,10"
    IsEnabled="{Binding Path=(dxe:ValidationService.HasValidationError), ElementName=validationContainer, Converter={StaticResource BooleanNegationConverter}}"/>
    </StackPanel>
    </Grid>
    </UserControl>

    MainViewModel.cs

    using DevExpress.Mvvm;
    using DevExpress.Mvvm.DataAnnotations;
    using System.Windows.Media;
    
    namespace Example.ViewModel {
    [POCOViewModel(ImplementIDataErrorInfo = true)]
    public class MainViewModel : ViewModelBase {
    static PropertyMetadataBuilder<MainViewModel, string> AddPasswordCheck(PropertyMetadataBuilder<MainViewModel, string> builder) {
    return builder.MatchesInstanceRule((name, vm) => vm.Password == vm.ConfirmPassword, () => "The passwords don't match.")
    .MinLength(8, () => "The password must be at least 8 characters long.")
    .MaxLength(20, () => "The password must not exceed the length of 20.");
    }
    public static void BuildMetadata(MetadataBuilder<MainViewModel> builder) {
    builder.Property(x => x.FirstName)
    .Required(() => "Please enter the first name.");
    builder.Property(x => x.LastName)
    .Required(() => "Please enter the last name.");
    builder.Property(x => x.Email)
    .EmailAddressDataType(() => "Please enter a correct email address.");
    AddPasswordCheck(builder.Property(x => x.Password))
    .Required(() => "Please enter the password.");
    AddPasswordCheck(builder.Property(x => x.ConfirmPassword))
    .Required(() => "Please confirm the password.");
    }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual string Email { get; set; }
    public virtual string Password { get; set; }
    public virtual string ConfirmPassword { get; set; }
    public void OnPasswordChanged() {
    this.RaisePropertyChanged(() => ConfirmPassword);
    }
    public void OnConfirmPasswordChanged() {
    this.RaisePropertyChanged(() => Password);
    }
    }
    }

    MainViewModel.vb

    Imports DevExpress.Mvvm
    Imports DevExpress.Mvvm.DataAnnotations
    Imports System.Windows.Media
    
    Namespace Example.ViewModel
    <POCOViewModel(ImplementIDataErrorInfo := True)> _
    Public Class MainViewModel
    Inherits ViewModelBase
    
    Private Shared Function AddPasswordCheck(ByVal builder As PropertyMetadataBuilder(Of MainViewModel, String)) As PropertyMetadataBuilder(Of MainViewModel, String)
    Return builder.MatchesInstanceRule(Function(name, vm) vm.Password = vm.ConfirmPassword, Function() "The passwords don't match.").MinLength(8, Function() "The password must be at least 8 characters long.").MaxLength(20, Function() "The password must not exceed the length of 20.")
    End Function
    Public Shared Sub BuildMetadata(ByVal builder As MetadataBuilder(Of MainViewModel))
    builder.Property(Function(x) x.FirstName).Required(Function() "Please enter the first name.")
    builder.Property(Function(x) x.LastName).Required(Function() "Please enter the last name.")
    builder.Property(Function(x) x.Email).EmailAddressDataType(Function() "Please enter a correct email address.")
    AddPasswordCheck(builder.Property(Function(x) x.Password)).Required(Function() "Please enter the password.")
    AddPasswordCheck(builder.Property(Function(x) x.ConfirmPassword)).Required(Function() "Please confirm the password.")
    End Sub
    Public Overridable Property FirstName() As String
    Public Overridable Property LastName() As String
    Public Overridable Property Email() As String
    Public Overridable Property Password() As String
    Public Overridable Property ConfirmPassword() As String
    Public Sub OnPasswordChanged()
    Me.RaisePropertyChanged(Function() ConfirmPassword)
    End Sub
    Public Sub OnConfirmPasswordChanged()
    Me.RaisePropertyChanged(Function() Password)
    End Sub
    End Class
    End Namespace

    DevExpress WPF | 下载试用

    DevExpress WPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件的衍伸产品,还是以数据为中心的商业智能产品,都能通过DevExpress WPF控件来实现。


    DevExpress技术交流群6:600715373      欢迎一起进群讨论

    更多DevExpress线上公开课、中文教程资讯请上中文网获取

  • 相关阅读:
    属性绑定与双向数据绑定
    vue基础
    tp5提交留言入库
    tp5表单提交
    TP5分页
    TP5模板与数据组合
    vue3.x使用Proxy做双向数据绑定总结
    vue2.x响应式原理总结
    HTML5移动端自适应解决方案
    springMVC实现文件上传
  • 原文地址:https://www.cnblogs.com/AABBbaby/p/16247949.html
Copyright © 2020-2023  润新知