Altinet
  • Home
  • Blog
  • Contact





Dataform, Ria Services, Combobox and Validation

On 02 Feb, 2011
Uncategorized
By : Bruno Samardzic
With 9 Comments
Views : 14563

As you may figured out from 1 of my previous posts, i’m not a big fan of Silverlight Dataform control, although I do like some of the capabilities presented there. In fact, after numerous frustrations with it, i decided to roll my own customization of it, rip out everything i didn’t need and adjust it to act the way i like it. You can find my first stab at it in this post.

That turned out to be one of the better decisions, although fighthing with the code mess inside the datafirn proved to be quite a challenge. Lately i had an issue with validation which i thought was just another dataform bug, but it proved to be a lot harder than it seemed at first. It’s well presented with the following picture i picked up from linkedIn:

Both of the fields are required to be filled out but the latter one is not highlighted. This case is only present if you try to submit unchanged value, this is very important as you’ll see later on.
Lets assume you have the following entities:

    public class Partner
    {
        [Key]
        public int Id { get; set; }
        
        [Required]
        public int? CountryId { get; set; }
		
	public Country Country{ get; set; }

    }

    public class Country
    {
        [Key]
        public int? Id { get; set; }
    }

Now, let’s say that you bound the combobox to Country property of a Partner entity:

<ComboBox Name="Country" SelectedItem="{Binding Country,Mode=TwoWay}" />
 

So you press an ok button and nothing really happens.
The problem
The main problem is not actually the dataform, but the way validation works with binding and the way Ria generates code for you. You see, every time you change value and lose focus, or you submit the data with an OK button, the bindings try to push the value to your entity, which means set the property. And the property in your generated file looks like this:

	public class Partner: Entity
	{ .
	 .
	 .
        /// <summary>
        /// Gets or sets the associated <see cref="Country"/> entity.
        /// </summary>
        [Association("Partner_Country", "CountryId", "Id", IsForeignKey=true)]
        public Country Country
        {
            get
            {
                if ((this._c == null))
                {
                    this._c = new EntityRef<Country>(this, "Country", this.FilterC);
                }
                return this._c.Entity;
            }
            set
            {
                Country previous = this.Country;
                if ((previous != value))
                {
                    this.ValidateProperty("Country", value);
                    if ((value != null))
                    {
                        this.CountryId = value.Id;
                    }
                    else
                    {
                        this.CountryId = default(Nullable<int>);
                    }
                    this._c.Entity = value;
                    this.RaisePropertyChanged("Country");
                }
            }
        }
	}

Pay attention to the part if (previous!=value). What that effectively means is that if your property came in as invalid, and you try to set that same value (for instance null) your property wouldn’t even go through the vaildation (that this.ValidateProperty(“Country”, value) line) !

A second problem alltogether would be that you can’t even put a required attribute on a property which already has the association attribute. You can put a required attibute on a CountryId field:

    public class Partner
    {
        [Key]
        public int Id { get; set; }
        
        [Required]
        public int? CountryId { get; set; }
		
	public Country Country{ get; set; }

    }

    public class Country
    {
        [Key]
        public int? Id { get; set; }
    }

But that wouldn’t then trigger validation for the Country if you defined your combobox like in the upper case.

So how to fix this?

Ok, let’s first define the combobox so that it uses the Required attribute of CountryId. The solution would look something like this:

<ComboBox ItemsSource="{Binding Data, ElementName=DF_CSource}" SelectedValue="{Binding CountryId,Mode=TwoWay}" 
          SelectedItem="{Binding Country,Mode=TwoWay}" SelectedValuePath="Id"/>

We are biniding the selectedValue to CountryId, and selected value is determined from SelectedItem.SelectedValuePath. This way the binding will trigger the validation of CountryId which would then highlight our combobox that there’s something wrong with it.
An alternative approach would be to define a custom rule which would check the value of Country property for null:

    public class Partner
    {
        [Key]
        public int Id { get; set; }
        
        public int? CountryId { get; set; }
		
	[CustomValidation(typeof(Validation),"ValidateAssociation")]
	public Country Country { get; set; }

    }

    public class Country
    {
        [Key]
        public int? Id { get; set; }
    }

This way, you could leave only the SelectedItem inside combobox and have full validation. My approach was the latter one, but i hid the custom validation behind some nice fluent interface so it’s easy to use.

Ok so now to the problem of original values not validating properly….
As i shown before, this is mainly the problem because dataform and controls rely on bindings to update the source and do validation consequently. Validation is not done if value never changes. One of the quick fixes you could introduce is to hook on the DataForm’s ValidatingItem event and do the following:

var entity= currentItem as Entity;
var context = new ValidationContext(entity, null, null);
var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(entity, context, validationResults, validateAllProperties);
entity.ValidationErrors.Clear();
validationResults.ForEach(entity.ValidationErrors.Add);

This will force the validation of entity and it will update the validation bindings. I have this implemented in my SlimForm, i did have to include additional reference to Domainservices.Client assembly, but i have that assembly defined either way in my project, plus i couldn’t find a more elegant solution. In general, there’s no easy way to solve this problem i’m afraid….
Anyway i hope this helps someone, if something’s not clear enough just post a comment. Cheers! The sample project is a bit different than the sample code, but i’ll think you’ll get the picture:)
Combobox sample project with updated SlimForm



Previous Post Next Post 

About The Author

Bruno Samardzic


Number of Posts : 45
All Posts by : Bruno Samardzic

Comments ( 9 )

  • Christ Holmes Mar 01 , 2011 at 1:24 pm / Reply

    Your naming conventions for classes and properties make this entirely too confusing to follow. I still have no idea how this works after reading your blog post.

    How about, instead of trying to make super-generic and meaningless class/property naems, you just name things based on something people can relate to, like say Products/Orders or BlogPosts/Comments… I mean, I am completely lost here. This makes no sense.

    • Peymankh May 01 , 2011 at 5:10 am / Reply

      NBecause you probably haven’t faced the problem.

  • kagjes Mar 01 , 2011 at 1:38 pm / Reply

    Yea, i agree that the naming convention is a bit confusing, i basically adjusted a combobox sample project which i previously downloaded , it’s by no means the way i write code:). The reason i went along with it is because the source is available for download, plus the whole example is composed of only 2 classes. But yea, i think blog post and comment would make more sense, even just for the code snippets, i’ll put it on my todo list. Thanks for the input!

  • Bryan Mar 22 , 2011 at 9:16 am / Reply

    I agree with the comments above. Object names are so generic they make it hard to understand whats what.

  • Bruno Mar 22 , 2011 at 9:57 am / Reply

    Ok, i updated the sample code, i hope it’s a bit clearer now. The point is basically the code you hook on dataform’s ValidatingItem event, so i think you will be good to go:)

  • vvalk Apr 20 , 2011 at 7:36 am / Reply

    Thanks! This saved my time and helped me very much.

  • Peymankh May 01 , 2011 at 5:15 am / Reply

    Seriously, thanks man. good one.

  • Pankaj Kumar Jun 26 , 2011 at 3:17 pm / Reply

    This is really a brilliant example of how the property gets validated and bound to the parent entity. I searched numerous MSDN pages, but thanks to Google to have me landed onto this page and finally could resolve the issue in just additional one line of code.

  • Shenbagaraj Dec 26 , 2011 at 6:16 am / Reply

    for combobox its working fine but for Radcombobox the event is not firing can anyone help


Leave a Reply to Bryan

Click here to cancel reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>





Recent Posts

  • Angular vs React: round 2
  • Why programming is hard
  • Orchard Workflows, undocumented gem
  • The React Redux
  • React.js invoicing CRUD application, part 2: Description

Recent Comments

  • Angshuman on Animation for starred grid rows and columns using xaml
  • Advanced Excel Training in Lucknow on Angular vs React: round 2
  • Reginald Sophomore on My example of Angularjs directive
  • Slobodan on Angular and Breeze – story so far.
  • Bruno Samardzic on Reaction to Ember-forged Durandal Angularly Knocking out my Backbone, or my JS MVC framework research conclusion.

Contact

Altinet d.o.o.

OIB: 97429091194

Čulinečka cesta 146, Zagreb

Tel: +385 (1) 2946 819

Mob: +385 (98) 210 756

IBAN: HR4323400091110406470

Latest tweets