I use a separate viewmodel in many (often older) webforms projects where I collect everything special special that should be displayed on page including css classes etc and regard the logic necessary as part of presentation logic. So in my case it would go in my GetDefaultViewmode() method where I create my viewmodel. If it's a common problem on many pages, I would add an interface to pagetypes with GetHeading or similar and use that instead for getting of heading. My viewmodels normally don't contain currentpage default properties, I use currentpage straight off for that to save some typing. If I need to add some logic to it or get from external data sources I gather everything to a viewmodel kind of object and use that instead. Been a while now since I had to get dirty with webforms though :)
Still, that approach doesn't work with the property webcontrol and on-page-edit. Otherwise I could simply do:
<%: CurrentPage.PageHeading ?? CurrentPage.Name %>
For dope support and webforms, custom renderers is an option
http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2012/10/Custom-renderers-for-properties/
or simply connect your control to your property with
someControl.ApplyEditAttributes<StartPage>(x => x.Links);
in code behind. Depends on what version you are using...
To be honest, I usually skip that part for some properties like that. Depends on the customer of course. EPiServer 6 and before wasn't very focused on dope support and I never heard a complaint about it.
From EPiServer 7 it's more or less required though :)
Creating a custom rendering control sure does the job, I think. But that won't solve the problem if a devloper is trying to access the property from an indexer, e.g. CurrentPage["PageHeading"]. But that might not be a problem.
We already have a bunch of custom rendering controls, so one more won't hurt :)
This is how I solved it. You need to decorate the property in the content type with the UI hint UIHints.Heading (a constant with the value 'heading'). I also added an extra guard and checked the property name, which probably is a bit overkill and not so nice to have hard-coded.
[TemplateDescriptor( Default = true, Inherited = true, TagString = UIHints.Heading)] public class HeadingControl : PropertyStringControl, IRenderTemplate<string>, IRenderTemplate { protected override bool ShouldCreateDefaultControls() { // We should always create default controls if we're rendering // PageHeading, since we will fall back on PageName which always // has a value. if (this.IsPageHading()) { return true; } return base.ShouldCreateDefaultControls(); } public override void CreateDefaultControls() { this.Controls.Add(this.GetControl()); } public override void CreateOnPageEditControls() { this.Controls.Add(this.GetControl()); if (this.PropertyIsEditableForCurrentLanguage()) { this.ApplyEditAttributes(); } } private Control GetControl() { var tag = this.CustomTagName ?? "h1"; var value = this.ToWebString(); // Fall back on PageName if PageHeading is null if (string.IsNullOrEmpty(value) && this.IsPageHading()) { var page = this.CurrentContent as PageData; if (page != null) { value = page.Name; } } var control = new HtmlGenericControl(tag) { InnerHtml = value }; this.CopyWebAttributes(control); return control; } private bool IsPageHading() { return this.PropertyData.Name.Equals("PageHeading"); } }
Hi,
What is your best approach to handle property fallbacks in your Webforms projects? This is very easy to handle in an MVC project, just override the get method in your content type model. However, this doesn't work with Webforms since the property webcontrol doens't use the model to fetch the property value. Instead it work against the PropertyDataCollection directly.
This is how I usually handle it when I want the PageHeading to have PageName as fallback:
But now I've run into some issues. E.g. when using the Language add-on and when the editor choose to copy the English content to another language. Then the PageHeading property will get a value, even though the English version didn't have a value in the PageHeading propery.