Domanda

I have made an ImageBlock with an ImageUrl property and a Description property. The ImageUrl is required.

[ContentType(
    DisplayName = "Image",
    Description = "Image with description and caption",
    GUID = "387A029C-F193-403C-89C9-375A2A6BF028",
    AvailableInEditMode = false)]
public class ImageBlock : BaseBlock
{
    [Required]
    [UIHint(UIHint.Image)]      
    [Display(
        Name = "Image Url",
        Description = "",
        GroupName = SystemTabNames.Content,
        Order = 10)]      
    public virtual Url ImageUrl { get; set; }

    [Display(
        Name = "Image Description",
        Description = "A description of the image",
        GroupName = SystemTabNames.Content,
        Order = 20)]      
    public virtual string Description { get; set; }

}

My ArticlePage uses this ImageBlock for its Image property, but it's not required to have an image in the article. However, if the editor chooses to have an image, the url should be required.

[Display(
    Name = "Image",
    Description = "",
    GroupName = SystemTabNames.Content,
    Order = 20)]
public virtual ImageBlock Image { get; set; }

But when I create a new instance of an ArticlePage I am prompted for the ImageUrl which EPiServer claims is required. Am I missing something?

È stato utile?

Soluzione

I found a way to build a custom attribute that checks gives an error if any other values than the required block property is set. So in my case, if for instance an editor enters a value for Image Description and tries to publish without specifying an ImageUrl, an errormessage will show.

The code looks like this:

public class RequiredBlockPropertyAttribute : ValidationAttribute
{
    private string _failedOnProperty = string.Empty;

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        return ValidateBlock(value, validationContext) 
            ? ValidationResult.Success 
            : new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    private bool ValidateBlock(object value, ValidationContext validationContext)
    {
        var type = validationContext.ObjectType.BaseType;
        if (type == null)
            return true;

        var properties = type.GetProperties().Where(prop => 
            prop.DeclaringType != null 
            && prop.DeclaringType.IsSubclassOf(typeof(BlockData)));

        foreach (var property in properties)
        {
            if (!property.Name.Equals(validationContext.DisplayName))
            {
                var val = property.GetValue(validationContext.ObjectInstance, null);
                if (val != null && (value == null || IsDateTimeMinValue(value)))
                {
                    _failedOnProperty = property.Name;
                    return false;
                }
            }
        }

        return true;
    }

    private static bool IsDateTimeMinValue(object value)
    {
        DateTime t;
        DateTime.TryParse(value.ToString(), out t);

        return t == DateTime.MinValue;

    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format(ErrorMessageString, name, _failedOnProperty);
    }

And the usage in the block:

    [RequiredBlockProperty(
        ErrorMessage = "{1} cannot be set without {0} defined")]
    [UIHint(UIHint.Image)]       
    [Display(
        Name = "Image Url", 
        Description = "", 
        GroupName = SystemTabNames.Content, 
        Order = 10)]       
    public virtual Url ImageUrl { get; set; } 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top