WCF RIA Servicesで公開したDTOに対してDataAnnotationでバリデーション
MetadataType属性でメタデータ用のクラスを指定します。メタデータ用のクラスには、Requiredとかバリデーションの属性を指定します。
[MetadataType(typeof(EmployeeMetadata))] public class Employee { [Key] public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } private class EmployeeMetadata { [Required(ErrorMessage = "必須です")] public string Name { get; set; } } }
メタデータ用のクラスを作るのがめんどいから、Employeeのプロパティに直接バリデーション用の属性をつけてMetadataType属性で自分自身を指定したらVisual Studioが落ちました。。。
サービスはこんな感じ。DomainServiceを継承します。
[EnableClientAccess()] public class MyDomainService : DomainService { public Employee GetEmployee() { return new Employee() { Id = 1, Name = "Hoge", Age = 30 }; } public void UpdateEmployee(Employee employee) { } }
以上が、サーバーサイド。
クライアントでは、ViewModelを作ります。
public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }
public class HomeViewModel : ViewModelBase { public event EventHandler Clicked; private readonly MyDomainContext _context = new MyDomainContext(); private Employee _employee; public HomeViewModel() { _clickCommand = new RelayCommand(OnClicked); _context.Load(_context.GetEmployeeQuery(), (op) => { if (!op.HasError) { Employee = op.Entities.First(); } }, null); } private readonly RelayCommand _clickCommand; public ICommand ClickCommand { get { return _clickCommand; } } private void OnClicked(object parameter) { var handler = Clicked; if (handler != null) { handler(this, EventArgs.Empty); } } public Employee Employee { get { return _employee; } set { _employee= value; OnPropertyChanged("Employee"); } } }
Employeeをサーバから取得してプロパティで公開してます。
ViewのXAMLとコードビハインドは以下のとおり。
<navigation:Page x:Class="BASample.Home" 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:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480" Style="{StaticResource PageStyle}"> <Grid x:Name="LayoutRoot"> <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}" > <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}"> <TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}" Text="{Binding Path=ApplicationStrings.HomePageTitle, Source={StaticResource ResourceWrapper}}"/> <TextBlock x:Name="ContentText" Style="{StaticResource ContentTextStyle}" Text="Home page content"/> <StackPanel Orientation="Horizontal"> <TextBlock>Name:</TextBlock> <TextBox Width="30" Text="{Binding Mode=TwoWay, Path=Employee.Name, ValidatesOnNotifyDataErrors=True}"></TextBox> </StackPanel> <Button x:Name="myButton" Content="Button" Height="23" Width="75" Command="{Binding Path= ClickCommand}" /> </StackPanel> </ScrollViewer> </Grid> </navigation:Page>
public partial class Home : Page { private HomeViewModel _viewModel = new HomeViewModel(); /// <summary> /// Creates a new <see cref="Home"/> instance. /// </summary> public Home() { InitializeComponent(); this.DataContext = _viewModel; _viewModel.Clicked += (e, s) => { NavigationService.Navigate(new Uri("/MyPage", UriKind.Relative)); }; this.Title = ApplicationStrings.HomePageTitle; } /// <summary> /// Executes when the user navigates to this page. /// </summary> protected override void OnNavigatedTo(NavigationEventArgs e) { } }
XAMLでは
<TextBox Width="30" Text="{Binding Mode=TwoWay, Path=Employee.Name, ValidatesOnNotifyDataErrors=True}"></TextBox>
コードビハンドでは
this.DataContext = _viewModel;
としておくのが大事。