翻譯|使用教程|編輯:龔雪|2022-05-07 10:15:20.120|閱讀 208 次
概述:本文主要介紹DevExpress MVVM架構下生成的POCO視圖模型,歡迎下載官方正式版體驗!
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
POCO(Plain Old CLR Objects)視圖模型簡化并加快了開發過程。
POCO 視圖模型允許您:
這允許您創建干凈、簡單、可維護和可測試的 MVVM 代碼,POCO 視圖模型與任何 WPF 控件完全兼容。
您可以使用在編譯時生成的視圖模型在編譯時為您的視圖模型生成樣板代碼。
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 對象時自動實現。 通過這個接口,子視圖模型可以訪問在主視圖模型中注冊的服務。
接口是 WPF 中數據驗證的標準機制,您可以使用此接口為每個單獨的屬性或整個對象定義驗證規則。 POCO 機制允許您基于定義的屬性或 Fluent API 自動實現接口。
要啟用此功能,請為您的視圖模型應用 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); } } }
類允許您根據指定的 屬性或 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擁有120+個控件和庫,將幫助您交付滿足甚至超出企業需求的高性能業務應用程序。通過DevExpress WPF能創建有著強大互動功能的XAML基礎應用程序,這些應用程序專注于當代客戶的需求和構建未來新一代支持觸摸的解決方案。 無論是Office辦公軟件的衍伸產品,還是以數據為中心的商業智能產品,都能通過DevExpress WPF控件來實現。
DevExpress技術交流群6:600715373 歡迎一起進群討論
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:慧都網