Для наиболее важных приложений я держу EF-классы совершенно отдельно. Я копирую свойства из каркаса сущности в модель представления, которая самостоятельно отслеживается.
Для небольших приложений я раньше этого не делал.
Вы можете увидеть подход, используемый в этом:
https://gallery.technet.microsoft.com/scriptcenter/WPF-Entity-Framework-MVVM-78cdc204
Это использует INotifyDataErrorInfo, и вы найдете IsValid в BaseEntity. Это довольно сложный класс, но многократно используемый.
Возможно, вы могли бы изменить рефлекс в BaseEntity. Легко, если вы в порядке, где бы вы ни были.
Аннотации находятся в отдельных классах друзей. Вы можете увидеть примеры в Customer.metadata.cs и Product.metadata.cs. Это частичные классы, которые добавляют наследование BaseEntity к классам сущностей. Следовательно, класс EF Customer наследует BaseEntity.
Пример:
using DataAnnotationsExtensions;
namespace wpf_EntityFramework.EntityData
{
[MetadataTypeAttribute(typeof(Product.ProductMetadata))]
public partial class Product : BaseEntity, IEntityWithId
{
public void MetaSetUp()
{
// In wpf you need to explicitly state the metadata file.
// Maybe this will be improved in future versions of EF.
TypeDescriptor.AddProviderTransparent(
new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Product),
typeof(ProductMetadata)),
typeof(Product));
}
internal sealed class ProductMetadata
{
// Some of these datannotations rely on dataAnnotationsExtensions ( Nuget package )
[Required(ErrorMessage="Product Short Name is required")]
public string ProductShortName { get; set; }
[Required(ErrorMessage = "Product Weight is required")]
[Min(0.01, ErrorMessage = "Minimum weight is 0.01")]
[Max(70.00, ErrorMessage = "We don't sell anything weighing more than 70Kg")]
public Nullable<decimal> Weight { get; set; }
[Required(ErrorMessage = "Bar Code is required")]
[RegularExpression(@"[0-9]{11}$", ErrorMessage="Bar codes must be 11 digits")]
public string BarCode { get; set; }
[Required(ErrorMessage = "Price per product is required")]
[Range(0,200, ErrorMessage="Price must be 0 - £200") ]
public Nullable<decimal> PricePer { get; set; }
private ProductMetadata()
{ }
}
}
}
Как говорится в комментарии.
Вам нужно вызывать этот Metasetup в каждом экземпляре. Если что-то не изменилось за последние несколько лет. Класс приятеля не просто подобран как в MVC.
Пример также возвращает ошибки преобразования из пользовательского интерфейса.
См. Шаблон в Dictionary1.
<ControlTemplate x:Key="EditPopUp" TargetType="ContentControl">
<ControlTemplate.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource ErrorToolTip}">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</ControlTemplate.Resources>
<Grid Visibility="{Binding IsInEditMode, Converter={StaticResource BooleanToVisibilityConverter}}"
Width="{Binding ElementName=dg, Path=ActualWidth}"
Height="{Binding ElementName=dg, Path=ActualHeight}"
>
<i:Interaction.Triggers>
<local:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}">
<e2c:EventToCommand
Command="{Binding EditVM.TheEntity.ConversionErrorCommand, Mode=OneWay}"
EventArgsConverter="{StaticResource BindingErrorEventArgsConverter}"
PassEventArgsToCommand="True" />
</local:RoutedEventTrigger>
<local:RoutedEventTrigger RoutedEvent="{x:Static Binding.SourceUpdatedEvent}">
<e2c:EventToCommand
Command="{Binding EditVM.TheEntity.SourceUpdatedCommand, Mode=OneWay}"
EventArgsConverter="{StaticResource BindingSourcePropertyConverter}"
PassEventArgsToCommand="True" />
</local:RoutedEventTrigger>
</i:Interaction.Triggers>