WPF IDataErrorInfo and NHibernate Validation - how to trigger a Validate? - wpf

I recently plugged the NHibernate validation into my app, I've decorated the properties of my domain objects with the NHibernate attributes as so ...
[NotEmpty, Length(Min = 1, Max = 40)]
public string Description { get; set; }
I've also implemented IDataErrorInfo on my Domain Object ...
public string this[string columnName]
{
get
{
var result = new ValidatorEngine().Validate(this);
_invalidValues = result.Where(x => x.PropertyName == columnName).Select(x => x.Message);
return _invalidValues.FirstOrDefault();
}
}
public string Error
{
get
{
return string.Empty;
}
}
The XAML looks like this
<TextBox Grid.Row="0" Grid.Column="3" Text="{Binding Path=Entity.Description, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" IsEnabled="{Binding IsEditable}" ></TextBox>
My issue is that when I create a new instance of my Domain object then the validate is not being called, as effectively the properties (such as the Description in my example) have not changed.
I was going to write a method to use reflection and set the properties to what they are already equal to in order to trigger the validate, but this dosnt seem a particularly efficient approach!!
Can someone put me back on track please?
Cheers,
Andy

Paul Stovell for has an excellent article for validation of business objects
http://www.codeproject.com/KB/cs/DelegateBusinessObjects.aspx

It was because the properties were Null and I needed another NHibernate validation decorator to take account of that (NotNullNotEmpty) rather than the NotEmpty I had used.
[NotNullNotEmpty, Length(Min = 1, Max = 40)]
public string Description { get; set; }

Related

Fill a combobox in WPF with a list of web services

I have a control like this:
<ComboBox x:Name="ComboTipo"
Height="23"
SelectionChanged="ComboTipo_SelectionChanged"
Width="450"
Canvas.Left="609"
Canvas.Top="26" />
And my code is:
ComboTipo.DisplayMemberPath = "Descripcion";
ComboTipo.SelectedValuePath = "IdTipoPersona";
ComboTipo.ItemsSource = myWebServices.dameTipos();
My web services returns a list for this object, this class is created in automatic when i add the reference to the web services:
public partial class TipoPersona {
private short idTipoPersonaField;
private string descripcionField;
/// <comentarios/>
public short IdTipoPersona {
get {
return this.idTipoPersonaField;
}
set {
this.idTipoPersonaField = value;
}
}
/// <comentarios/>
public string Descripcion {
get {
return this.descripcionField;
}
set {
this.descripcionField = value;
}
}
}
But the problem is:
The combobox displays the data types for each element of the list, and i want display the Descripcion.
Can you help me plis! Thanks
What does IdTipoPersona look like? Is it a class you created? If so, you may need to reference the property that you want displayed. It would look something like this:
ComboTipoPersona.SelectedValuePath = "IdTipoPersona.Text";
Where Text would be replaced by the property. It is really hard to judge otherwise what is going on with knowing a little more about the object structure that myWebServices.dameTipos() returns.
EDIT
Ok I was able to simulate your problem and simulate a solution as well.
Your issue is in the Tipos class. There are a couple of things necessary when binding to a combobox with a custom class.
First off, you will want to add accessors and mutators (getters and setters) to IdTippoPersona and Descripcion.
You should add a constructor that assigns to those properties with parameters.
It is usually a good idea to add a default constructor.
The finished code will look like this:
public class Tipos
{
public int IdTipoPersona { get; set; }
public string Descripcion { get; set; }
public Tipos(int id, string descripcion)
{
IdTipoPersona = id;
Descripcion = descripcion;
}
}
I found the asnwer if someone needs it.
We need create a class intermediate class but we were working with entity framework, for this way, we need add the intermediate class like complex type in my model (entity framework).
And also we need override this class.
And it works so well.
Thanks for all #Goody

No design time data with entity framework 5 in Visual Studio

Hi I build a simple test solution in VS 2012 with two projects.
One is a Class library and the other a WPF application.
Both use .NET 4.5.
In the class library I add an EF element (DataFirst) which maps a simple table.
Next I reference this project in my WPF project.
Add EF from Nuget and using a very simple MVVM like pattern I add a class which looks like this (please note - this is not production code - it's just to reproduce the problem).
public class Class1 {
public static Helper TheHelper { get; set; }
public Class1() {
TheHelper = new Helper();
}
}
public class Helper {
public Helper() {
Nam = "aaa";
}
string connectionString = "metadata=res://*/Mod.csdl|res://*/Mod.ssdl|res://*/Mod.msl;provider=System.Data.SqlClient;provider connection string=\";data source=.\\sqlx8r2;initial catalog=FCdata;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework\"";
public string Nam { get; set; }
#region PCs
private List<PC> m_lPCs;
public List<PC> PCs {
get {
if(m_lPCs == null) {
try {
using(FCdataEntities dE = new FCdataEntities(connectionString)) {
m_lPCs = dE.PCs.ToList();
}
}
catch(Exception eX) {
m_lPCs = new List<PC>();
m_lPCs.Add(new PC() { Description = eX.Message });
}
}
return m_lPCs;
}
set {
if(m_lPCs != value) {
m_lPCs = value;
//RaisePropertyChanged(() => PCs);
}
}
}
#endregion
I also extended the context class like this:
public partial class FCdataEntities : DbContext {
public FCdataEntities(string strCon) : base(strCon) {
}
}
So I can pass the connection string which I copy from app.config.
In my main window I do a simple binding like this:
xmlns:local="clr-namespace:EFTest"
Title="MainWindow" Height="350" Width="1525">
<Window.Resources>
<local:Class1 x:Key="dG" />
</Window.Resources>
<Grid DataContext="{Binding Path=TheHelper, Source={StaticResource dG} }">
<Grid.RowDefinitions>
<RowDefinition Height="17*"/>
<RowDefinition Height="143*"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding Nam}" />
<ListBox ItemsSource="{Binding PCs}" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
The solution works fine at runtime.
But in the VS Designer I get an exception shown in my "dummy obect" which I create in the catch block of the property.
Could not load file or assembly 'Windows, Version=255.255.255.255, Culture=neutral, ContentType=WindowsRuntime' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
What I need is data at design time - and no "dummy data" - instead I want to get it from the DB - avoiding the use of EF (and use linq2sql for an example) works like a charm.
Did I make a mistake with the connection string (or so) - or is there simply a problem in EF 5.0?
This particular error is a known issue in Entity Framework 5 with the Visual Studio & Expression designers and has been fixed in the Entity Framework 6 source code. However there are other design time errors which I haven't been able to resolve which prevent Entity Framework code from running in the designer.

Validation of a combobox in Silverlight 4

I'm trying to understand how validation works for a combo box when its ItemsSource is bound to a ObserableCollection of complex types. I am using RIA as the serivce to connect the client tier to the middle tier. Also not sure if this makes a difference the combobox control is inside a dataform. I have done alot of reading on this and found this article to be the most useful: http://www.run80.net/?p=93
So firstly my entity: I have a field decorated like so:
[Required]
public virtual long FrequencyId { get; set; }
[Include]
[Association("TreatmentFrequencyToTreatmentRecordAssociation", "FrequencyId", "Id", IsForeignKey = true)]
public virtual TreatmentFrequency Frequency
{
get
{
return this.frequency;
}
set
{
this.frequency = value;
if (value != null)
{
this.FrequencyId = value.Id;
}
}
}
Now I belive that I cannot set the [Required] annotation on an association but instead on the foreign key id (what the above article says).
The actual Treatment Frequency class looks like this:
public class TreatmentFrequency
{
[Key]
public virtual long Id { get; set; }
[Required]
[StringLength(10)]
public virtual string Code { get; set; }
[Required]
[StringLength(40)]
public virtual string Name { get; set; }
public override bool Equals(object obj)
{
obj = obj as TreatmentFrequency;
if (obj == null)
{
return false;
}
return this.Id == ((TreatmentFrequency)obj).Id;
}
public override int GetHashCode()
{
return this.Name.GetHashCode();
}
}
I have overriden the Equals and GetHashCode method becuase in another article it said that when in a collection you need to override the equals to match on the key otherwise when you use SelectedItem although all the values would be the same between the item in the collection and the selecteditem they would be two different instances and thus not match with the default implementation of Equals.
Now my xaml looks like this:
<df:DataField Label="Frequency">
<ComboBox SelectedItem="{Binding Path=CurrentItem.Frequency, Mode=TwoWay}" ItemsSource="{Binding Path=Frequencies}" DisplayMemberPath="Name" SelectedValue="{Binding Path=CurrentItem.FrequencyId, Mode=TwoWay}" SelectedValuePath="Id"/>
</df:DataField>
To be honest the above doesn't make much sense to me, I could remove SelectedValue and SelectedValuePath and the form would still work as expected (without validation) I thought that Selected Value would point to the complex type E.g. CurrentItem.Frequency and then the SelectedValuePath would be the underlying "Name" property. However I also understand what the author is trying to do in that the [Required] tag isn't on the association but the foreign key id E.g. CurrentItem.FrequencyId, so it must have to go somewhere.
Now a final compelexity is that this form is part of a wizard so I am not able to validate the entire object, instead I manually have to validate certain field which are only being populated in this particular wizard step. To do this I created the method:
public void ValidateProperty(object value, string propertyName)
{
var results = new List<ValidationResult>();
Validator.TryValidateProperty(value, new ValidationContext(this.TreatmentRecord, null, null) { MemberName = propertyName }, results);
foreach (var error in results)
{
this.TreatmentRecord.ValidationErrors.Add(error);
}
}
In my view model I have a method IsValid which is called before the wizard is allowed to navigate to the next step and then I call the above method like so:
public bool IsValid
{
get
{
this.treatmentRecordWizardContext.ValidateProperty(this.treatmentRecordWizardContext.TreatmentRecord.Frequency, "Frequency");
this.treatmentRecordWizardContext.ValidateProperty(this.treatmentRecordWizardContext.TreatmentRecord.FrequencyId, "FrequencyId");
this.OnPropertyChanged(() => this.CurrentItem);
if (this.treatmentRecordWizardContext.TreatmentRecord.ValidationErrors.Count == 0)
{
return true;
}
return false;
}
}
With all of the above code the validation is completly ignored when the combobox is left empty. I have not templated the combobox itself so I am really at a loss as to why its not working and really which part of the solution is at fault, is it the bindings or is it the entitys in the RIA not defined correctly!
Hope someone can help I've spent far too long trying to get this to work, I assume this must be done reqularly by other developers so I'm hoping its a simple fix.
This was actually a simple problem in th end, I assumed that the [Required] annotation would check that the association was present and not null. It seems that all it actually does is check that in this case that FrequencyId is not null. And there was the problem in that I was using a long and not a nullable long (long?). Once I made the change to make them nullable the validation started working as expected even with the bindings which made no sense to me. If anyone could explain them that would be great!
Phil

Argument validation in custom activity designer

I am having problems getting validation to work properly in the designer for my custom activity. The simplest sample to reproduce the behavior is as follows:
I have a custom WF4 activity with a dynamic collection of arguments stored in a dictionary:
[Designer(typeof(DictionaryActivityDesigner))]
public class DictionaryActivity : NativeActivity
{
[Browsable(false)]
public Dictionary<string, InArgument> Arguments { get; set; }
public InArgument<string> StringArg { get; set; }
public DictionaryActivity()
{
Arguments = new Dictionary<string, InArgument>();
}
protected override void Execute(NativeActivityContext context)
{ }
}
In the designer I dinamically create expression text boxes for editing these arguments. The user has the possibility to define the arguments and their types in a separate modal window, but for the sake of simplicity I have fixed the arguments in this sample:
public partial class DictionaryActivityDesigner
{
private Dictionary<string, Type> definition;
public DictionaryActivityDesigner()
{
definition = new Dictionary<string, Type>
{
{ "String Arg", typeof(string) },
{ "Int Arg", typeof(int) }
};
InitializeComponent();
}
public void InitializeGrid(Dictionary<string, Type> arguments)
{
ArgumentsGrid.RowDefinitions.Clear();
ArgumentsGrid.Children.Clear();
int gridRow = 0;
foreach (var arg in arguments)
{
ArgumentsGrid.RowDefinitions.Add(new RowDefinition());
var label = new Label()
{
Content = arg.Key + ":"
};
Grid.SetRow(label, gridRow);
Grid.SetColumn(label, 0);
ArgumentsGrid.Children.Add(label);
var textbox = new ExpressionTextBox()
{
ExpressionType = arg.Value,
OwnerActivity = ModelItem,
UseLocationExpression = false
};
var binding = new Binding()
{
Mode = BindingMode.TwoWay,
Converter = new ArgumentToExpressionConverter(),
ConverterParameter = "In",
Path = new PropertyPath("ModelItem.Arguments[(0)]", arg.Key)
};
textbox.SetBinding(ExpressionTextBox.ExpressionProperty, binding);
Grid.SetRow(textbox, gridRow);
Grid.SetColumn(textbox, 1);
ArgumentsGrid.Children.Add(textbox);
gridRow++;
}
}
private void ActivityDesigner_Loaded(object sender, RoutedEventArgs e)
{
InitializeGrid(definition);
}
}
Below is the XAML for the designer:
<sap:ActivityDesigner x:Class="ActivityValidation.DictionaryActivityDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
Loaded="ActivityDesigner_Loaded">
<sap:ActivityDesigner.Resources>
<ResourceDictionary>
<sapc:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />
</ResourceDictionary>
</sap:ActivityDesigner.Resources>
<StackPanel Orientation="Vertical">
<Grid Name="ArgumentsGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition MinWidth="250" />
</Grid.ColumnDefinitions>
</Grid>
<sapv:ExpressionTextBox ExpressionType="s:String"
OwnerActivity="{Binding ModelItem}"
Expression="{Binding ModelItem.StringArg, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}" />
</StackPanel>
</sap:ActivityDesigner>
The InitializeGrid method adds the expression text boxes for the arguments to the ArgumentGrid. Under it I have a separate statically defined expression text box for a fixed argument in the activity to demonstrate the (almost) desired behavior.
Now for the problems:
Invalid expressions for the dynamic arguments only cause the error icon to appear beside the text box but it doesn't propagate to the top bar of the designer as it does if there is an error in the statically defined text box.
If I close the designer in such invalid state (and save the definition), the eror icon correctly propagates to the top bar even if the error is only in the dynamic text box. Though the behavior gets even more strange afterwards. After changing the values for the arguments, now even the error icon beside the text box doesn't work consistently any more.
If I delete the contents of a dynamic text box completely, the value in the dictionary gets set to null which manifests in the workflow definition as <x:Null x:Key="String Arg" /> instead of <InArgument x:TypeArguments="x:String" x:Key="String Arg">["a"]</InArgument> or just ommiting the entry as is the case before editing the expression for the first time. If I reopen such a workflow even the statically created text box doesn't work properly any more (the error icon is only visible when text box is focused and it doesn't propagate to the top any more).
It seems obvious that I am doing something wrong when creating the dynamic text boxes. What would be the correct way of doing it? Is there any example available for creating a designer for a custom activity with dynamic number of arguments?
EDIT:
For those interested:
There was some more discussion on MSDN Forums where I have also posted the issue.
As a result of that discussion, I've also filed a report on Microsoft Connect.
I encountered the problem I described here while trying to create a designer for a dynamic collection of arguments in an activity. I managed to work around the problem by using the built-in DynamicArgumentDialog window. I had to restructure my activity to accept a single collection of both input and output arguments:
public Dictionary<string, Argument> Arguments { get; set; }
instead of two separate collections I was using before:
public Dictionary<string, InArgument> InArguments { get; set; }
public Dictionary<string, OutArgument> OutArguments { get; set; }
I found the Custom Activity to Invoke XAML Based Child Workflows very helpful when making this work.

MVVM light datagrid loading from two relational database tables

How to Load DataGrid with two related tables using MVVM light, I am using .NET RIA and silverlight 4.
for example if my data tables are:
userInfo-
userID, Name, AddressID
Address -
AddressID, StreetName, Zip
how can i create datagrid that displays [Name, StreetName, ZIp]
First of all you have to include Address table in GetQuery of UserInfo in your DomainService class like below...
[Query]
public IQueryable<UserInfo> GetUserInfos()
{
return this.ObjectContext.UserInfos.Include("Address");
}
then in the metadata file u have to add [Include] just above the
[Include]
public Addresses Address{ get; set; }
public int AddressID { get; set; }
Now Build the solution.
Now in the Xaml you can use like this
<sdk:DataGrid ItemsSource="{Binding UserList, Mode=TwoWay}" SelectedItem="{Binding CurrentUser, Mode=TwoWay}" Margin="0,0,0,2" AutoGenerateColumns="False">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
<sdk:DataGridTextColumn Header="Street Name" Binding="{Binding Path=Address.StreetName}"/>
<sdk:DataGridTextColumn Header="Zip" Binding="{Binding Path=Address.Zip}"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
There are a couple approaches possible here. I will explain both that come to mind. First, is using a relationship already defined in your database. Second is to return via a custom model class.
Option 1:
I will assume you have created an Entity Framework Model (with a relationship) from your database on the Web Project and created the DomainService to host the Model. !!!One key to do when you create the model is to create meta-data classes for the models!!! (I missed this the first few times through, and it is critical to modify the behavior of your models, such as you are needing here)
Within the meta-data model, you will find the association property, and decorate it with the [Include] attribute. Here is an example I have from another project with a WorklanDetail, where I want to return the associated Assignments:
[MetadataTypeAttribute(typeof(WorkplanDetailMetadata))]
public partial class WorkplanDetail
{
internal sealed class WorkplanDetailMetadata
{
[Include]
public EntityCollection<Assignment> Assignments { get; set; }
}
}
then, you can just reference the property in your Silverlight application, and viola your address data is available.
To bind a single Entity (EntityReference, not collection) then you will just use you property to access the sub-entity on your datagrid's binding... For exmaple:
Text="{Binding Path=Address.StreetName}"
That is the simplest method that I know of.
Option 2 requires creating your own custom class (you must at least have a property decorated with the [Key] attribute ot facilitate the transfer to/from the client). Here is an example, I have used to get foldersearch result information:
public class FolderSearchResult
{
[Key]
public string EFOLDERID { get; set; }
public string Subject { get; set; }
public string FolderName { get; set; }
}
The key being that the EFOLDERID propety has the [Key] attribute, which uniquely identifies each item just like a PK in a database.
Then in your service class you can return this kind of like this:
public IEnumerable<FolderSearchResult> GetFolderResults(string search)
{
var query = from ge in this.ObjectContext.Generic_Engagement
from f in this.ObjectContext.eFolders
where ge.EFOLDERID == f.eFolderID &
f.eArchived == 0 &
f.eSubject.Contains(search) &
(from wp in this.ObjectContext.Workplans
where wp.EFOLDERID == f.eFolderID
select wp).Count() == 0 &
(from r in this.ObjectContext.Resources
where r.EFOLDERID == f.eFolderID
select r).Count() == 0
select new FolderSearchResult()
{
EFOLDERID = f.eFolderID,
FolderName = f.eFolderName,
Subject = f.eSubject
};
return query.AsEnumerable<FolderSearchResult>();
}
Couple of notes about this approach:
This works best in my opinion when you don't need Read-Only access. If you are doing updates/inserts/deletes use the first approach.
This works well to help when you need to create some logical object between completely different data sources (maybe userid and employeeid from database, plus display name, site location, etc. from Active Directory).
Updating this way is possible, but you must do a bit more work to separate out your items and update everything properly.
In summary, I would suggest using the first approach, unless the following occur: You need a logical object which crosses data-storage (separate db sources), or you need fast read-only access (such as ItemSource binding for drop-down list).
Offloading sorting and filtering logic to the server, even at the expense of additional entities loaded in memory so that your client can remain fast pays dividends in my experience. Using local sort in a CollectionViewSource or something can do the same, but just a few of these can really start slowing your application speed.

Resources