I might be wrong, but it seems to me that you will need to iterate up the tree yourself. However, I wouln't base this on the property name; I'd rather make my own version of ContentArea (by extending on the existing one), and thus have my own InheritingContentArea, which would inherit if not set (as long as there was something to inherit from, otherwise it would simply be empty). Haven't tried this myself, but I think it should work. Good luck! ...and keep us updated on this, it seems like this is something that could come in handy for some projects...
If you place an EPiServer:Property web control in your masterpage and set its PropertyName to your contentarea name and then set the PageLink to point to the startpage in your example the property will get it's content from that area. It's pretty neat.
Anders: Yeah I guess I need to do something like that but it feels like I'm over working myself. Don't understand why I can't just use a dynamic property for this.
Per: That would be dynamic though. That would just change the value if its set on that specific page. If you would go to a child page of that page it would still show the start page content. Also, I'm using MVC but i get what your mean :)
I missed that you wanted to be able to change it on subpages.
I guess that you could have a dynamic property of type contentarea. Then you have a page property of type contentarea where you in the property set programatically sets dynamic property. Not a pretty solution thought..
Ended up doing this which solves my problem, but i think ill make a ticket to episerver to hear their take on this and see if there is a better way
public object GetInheritedPagePropertyValue(PageData contentData, string propertName)
{
var value = contentData[propertName];
if (value == null && !contentData.ParentLink.CompareToIgnoreWorkID(ContentReference.RootPage))
{
return GetInheritedPagePropertyValue(contentData.ParentLink.GetPage(), propertName);
}
if (value != null)
return value;
return null;
}
At first i was tryign to do this method alot more generic and passing an expression instead of a string. Then I realized that if I wanted this method to be able to handle all page types and not just the ones that have the property i want on them, then the way i built my method wouldn't work because I was specifying which pagetype to use when making the expression Maybe its still solveable in some way but i'm tired at the moment and the deadline is getting closer so this will have to do. If you want to continue where i left of on my "good looking code" then I've pasted in below
public TPropertyValue GetInheritedPagePropertyValue<TPageData, TPropertyValue>(TPageData contentData, Expression<Func<TPageData, TPropertyValue>> expression) where TPageData : PageData
{
string propertName = GetPropertyName(expression);
var value = contentData[propertName];
if (value == null && !contentData.ParentLink.CompareToIgnoreWorkID(ContentReference.RootPage))
{
return GetInheritedPagePropertyValue(contentData, expression);
}
return default(TPropertyValue);
}
public string GetPropertyName<TContentType, TValue>(Expression<Func<TContentType, TValue>> contentData)
{
string result;
if (TryGetPropertyName(contentData.Body as MemberExpression, out result))
{
return result;
}
var unaryExpression = contentData.Body as UnaryExpression;
if (unaryExpression != null && TryGetPropertyName(unaryExpression.Operand as MemberExpression, out result))
{
return result;
}
throw new FormatException("Unsupported expression. The body of the expression must either be a MemberExpression or a UnaryExpression.");
}
public bool TryGetPropertyName(MemberExpression memberExpression, out string propertyName)
{
if (memberExpression != null)
{
propertyName = memberExpression.Member.Name;
return true;
}
propertyName = null;
return false;
}
Oh well, looks like good brain workout :) I'll take a look: will come back if I get something meaningful out of this. Anyway: good start for an extension method.
Ended up making an extension method for this, doing aproximately what your original code did. Still not generic but..
public static class ContentDataExtensions { public static T GetPropertyValueRecursive<T>(this ContentData contentData, string propertyName) { var val = contentData.GetPropertyValue(propertyName, default (T)); if (val != null || PageEditing.PageIsInEditMode) return val; // get parent content data var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>(); var parent = contentLoader.Get<ContentData>(((IContent) contentData).ParentLink); if (parent == null) // this must be the root page, return null or whatever return default(T); return parent.GetPropertyValueRecursive<T>(propertyName); } }
Could someone give me some guidelines on how do make a contentarea that inherits its values (i.e. blocks) so that i can specify the content on e.g. the start page and all child pages of start will display the same values in that contentarea.
I also want to be able to change the values on a child page and instead inherit from that page on that pages children.
Sounds like I'm describing dynamic properties don't it? I tried i using that but first of all the property isnt editable when viewing the dynamic properties "form" and if I would to render the contentarea like this: @Html.PropertyFor(x => x.CurrentPage["TestContentArea"]) I will get the following exception:
Unsupported expression. The body of the expression must either be a MemberExpression or a UnaryExpression
I suppose that I could put contentareas with the same name on all pagetypes that I want to be able to change the content and make sure they have the same name and when creating my viewmodel for my layout i could just search upwards until i find a page that has this property set and send this to the viewmodel... But there got to be a better way? interate upwards in the page hierarchy can't be good for performance.
Taking any suggestions.