Question

I'm creating in a Portable Library Class my domain objects. Those one should implement INotifyPropertChanged and INotifyDataErrorInfo

So, my domain classes should implement this base class

public abstract class DomainObject : INotifyPropertyChanged, INotifyDataErrorInfo
{
    private ErrorsContainer<ValidationResult> errorsContainer;

    protected DomainObject() {}

    public event PropertyChangedEventHandler PropertyChanged;
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public bool HasErrors
    {
        get { return this.ErrorsContainer.HasErrors; }
    }

    protected ErrorsContainer<ValidationResult> ErrorsContainer
    {
        get
        {
            if (this.errorsContainer == null)
            {
                this.errorsContainer =
                    new ErrorsContainer<ValidationResult>(pn => this.RaiseErrorsChanged(pn));
            }

            return this.errorsContainer;
        }
    }

    public IEnumerable GetErrors(string propertyName)
    {
        return this.errorsContainer.GetErrors(propertyName);
    }

    protected void RaisePropertyChanged(string propertyName)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    protected void ValidateProperty(string propertyName, object value)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            throw new ArgumentNullException("propertyName");
        }

        this.ValidateProperty(new ValidationContext(this, null, null) { MemberName = propertyName }, value);
    }

    protected virtual void ValidateProperty(ValidationContext validationContext, object value)
    {
        if (validationContext == null)
        {
            throw new ArgumentNullException("validationContext");
        }

        List<ValidationResult> validationResults = new List<ValidationResult>();
        Validator.TryValidateProperty(value, validationContext, validationResults);

        this.ErrorsContainer.SetErrors(validationContext.MemberName, validationResults);
    }

    protected void RaiseErrorsChanged(string propertyName)
    {
        this.OnErrorsChanged(new DataErrorsChangedEventArgs(propertyName));
    }

    protected virtual void OnErrorsChanged(DataErrorsChangedEventArgs e)
    {
        var handler = this.ErrorsChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }
}

But I realized that in this line

        this.ValidateProperty(new ValidationContext(this, null, null)
           { MemberName = propertyName }, value);

I can't create the object ValidationContext because it does not have any constructor. How can I do to create the new one?

UPDATE According to my Intellisense, this contains.

#region Assembly System.ComponentModel.DataAnnotations.dll, v2.0.5.0
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.0\Profile\Profile46\System.ComponentModel.DataAnnotations.dll
#endregion

using System;
using System.Collections.Generic;

namespace System.ComponentModel.DataAnnotations
{
    // Summary:
    //     Describes the context in which a validation check is performed.
    public sealed class ValidationContext
    {
        // Summary:
        //     Gets or sets the name of the member to validate.
        //
        // Returns:
        //     The name of the member to validate.
        public string DisplayName { get; set; }
        //
        // Summary:
        //     Gets the dictionary of key/value pairs that is associated with this context.
        //
        // Returns:
        //     The dictionary of the key/value pairs for this context.
        public IDictionary<object, object> Items { get; }
        //
        // Summary:
        //     Gets or sets the name of the member to validate.
        //
        // Returns:
        //     The name of the member to validate.
        public string MemberName { get; set; }
        //
        // Summary:
        //     Gets the object to validate.
        //
        // Returns:
        //     The object to validate.
        public object ObjectInstance { get; }
        //
        // Summary:
        //     Gets the type of the object to validate.
        //
        // Returns:
        //     The type of the object to validate.
        public Type ObjectType { get; }

        // Summary:
        //     Returns the service that provides custom validation.
        //
        // Parameters:
        //   serviceType:
        //     The type of the service to use for validation.
        //
        // Returns:
        //     An instance of the service, or null if the service is not available.
        public object GetService(Type serviceType);
    }
}
Was it helpful?

Solution

This is something we missed. In early builds of Visual Studio 2012, IServiceProvider was not available due to it being removed from Windows Store apps. Due to the way that portable was modeled underneath this meant no other platform combination could expose it either. This caused anything that had a dependency on it to be removed, hence the ValidationContext constructor. Later we added IServiceProvider back, and missed this constructor. I've filed a bug internally, and we'll see if we can re-add it in a future version.

To workaround this, you have a couple of options:

1) Target .NET Framework 4.5 and Silverlight 5. These versions added new constructors which do not have a dependency on IServiceProvider.

2) Use Reflection to call the constructor. Make note that this will only work in .NET Framework and Silverlight. It will not work in Windows Store apps because it does not expose this constructor (it will throw InvalidOperationException).

3) Have the platform-specific projects (ie .NET Framework 4.0 or Silverlight 4) projects create the ValidationContext themselves, and have it injected into the portable library. Either you can do this via some sort of dependency injection, or via a platform-adapter pattern that I call out in Create a Continuous Client Using Portable Class Libraries under the Converting Existing Libraries to PCLs section.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top