I want to include an ascx file with navigator bar. There are two versions, one shows up when user is not logged in and one is for logged user.
This is what I'm lookin for
<div class="navigator">
<%
if(Session["loggedin"] == null) {
Include this file <uc1:nav runat="server" ID="nav" />
} else {
Include this file <uc1:nav runat="server" ID="nav2" />
}
%>
</div>
This is how I can link one of the nav... but I have no idea how to make this path into if/else statment
Tried to do some things inside of <% %> but.... without any success.
Could anyone help me?
Appeareantly I figured it out.
Here is what I did.
<% if(Session["loggedin"] == null) { %>
<uc1:nav runat="server" ID="nav" />
<% } else { %>
<uc1:nav runat="server" ID="nav2" />
<% } %>
Related
I am new to ASP.NET. As a follow up question from THIS POST I have the following .Net Control in Ektron that I would like to display in my webpage template.
Control:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="Gallery.ascx.cs" Inherits="Source_Controls_Alumni_Gallery" %>
<asp:ListView ID="uxPhotoGallery" runat="server" ItemPlaceholderID="itemPlaceholder">
<LayoutTemplate>
<ul>
<asp:PlaceHolder ID="itemPlaceholder" runat="server" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<%--
I'm mixing up two different ways of referencing the incoming data. One is by casting
the DataItem to the incoming type, which gives you intellisense access to the properties.
The other is more of a dictionary approach in which you have to type out the property name
as a string.
I really like the casting approach, but it's mega-wordy.
--%>
<a href="<%#((Ektron.Custom.ViewModels.PressPhotoViewModel)Container.DataItem).ImageUrl %>">
<img src="<%#((Ektron.Custom.ViewModels.PressPhotoViewModel)Container.DataItem).ImageUrl %>" alt="<%#Eval("Description") %>" />
<div><%#Eval("Description") %></div>
</a>
</li>
</ItemTemplate>
</asp:ListView>
and code behind:
using Ektron.Custom.SmartForms;
using System;
using System.Linq;
public partial class Source_Controls_Alumni_Gallery : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
var pressPhotoManager = new PressPhotoManager();
// Whichever folder Id...
var photos = pressPhotoManager.GetList(75);
if (photos != null && photos.Any())
{
uxPhotoGallery.DataSource = photos;
uxPhotoGallery.DataBind();
}
}
}
I would like to insert the control into this template:
<%# Page Title="" Language="C#" MasterPageFile="~/Source/Masterpages/MainMaster.master" AutoEventWireup="true" CodeFile="AlumniJobOpenings.aspx.cs" Inherits="Source_Templates_AlumniJobOpenings" %>
<%# Register Src="~/Source/Controls/SubHeader.ascx" TagPrefix="uc1" TagName="SubHeader" %>
<%# Register Src="~/Source/Controls/Shared/PrimarySection.ascx" TagPrefix="uc1" TagName="PrimarySection" %>
<%# Register Src="~/Source/Controls/JoinUs/StaffAndParalegals/SPOpenings.ascx" TagPrefix="uc1" TagName="SPOpenings" %>
<%# Register Src="~/Source/Controls/JoinUs/StaffAndParalegals/SPFilters.ascx" TagPrefix="uc1" TagName="SPFilters" %>
<%# Register Src="~/Source/Controls/Shared/RelatedContentModules.ascx" TagPrefix="uc1" TagName="RelatedContentModules" %>
<%# Register Src="~/Source/Controls/JoinUs/StaffAndParalegals/SPContactDetails.ascx" TagPrefix="uc1" TagName="SPContactDetails" %>
<%# Register Src="~/Source/Controls/Shared/TextImageAssetBlockModules.ascx" TagPrefix="uc1" TagName="TextImageAssetBlockModules" %>
<%# Register Src="~/Source/Controls/Shared/TextLinkBlockControl.ascx" TagPrefix="uc1" TagName="TextLinkBlockControl" %>
<%# Register TagPrefix="sp" TagName="Spinner" Src="~/Source/Controls/Alumni/Gallery.ascx" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<uc1:SubHeader runat="server" ID="SubHeader" />
<div class="container non-responsive">
<div class="row">
<div class="col-sm-8 alpha">
<uc1:PrimarySection runat="server" ID="PrimarySection" />
<div class="primary">
<div class="container non-responsive">
<div class="row">
<div class="col-sm-8 alpha">
<div class="primary">
IMAGE GALLERY LIST SHOULD BE INSERTED HERE.
</div>
</div>
<div class="col-sm-4 beta">
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-4 beta">
<uc1:SPContactDetails runat="server" ID="SPContactDetails" />
<uc1:SPFilters runat="server" ID="SPFilters" Heading="Staff and Paralegal Openings" Text="Select an office below to learn more about current opportunities" />
<uc1:RelatedContentModules runat="server" ID="RelatedContentModules" />
<uc1:TextLinkBlockControl runat="server" ID="TextLinkBlockControl" />
<uc1:TextImageAssetBlockModules runat="server" ID="TextImageAssetBlockModules" />
</div>
</div>
</div>
</asp:Content>
Here's your line from the top:
<%# Register TagPrefix="sp" TagName="Spinner" Src="~/Source/Controls/Alumni/Gallery.ascx" %>
And a similar line used to register another control in the same page:
<%# Register Src="~/Source/Controls/SubHeader.ascx" TagPrefix="uc1" TagName="SubHeader" %>
Now, take a look at the control placement for the pre-existing item referenced above.
<uc1:SubHeader runat="server" ID="SubHeader" />
What you'll find is that the placement tag is made up of configured properties in the <%# Register ... %> line. Specifically, the TagPrefix and TagName values. You'll use those values to set up your own control placement, following this format:
<TagPrefix:TagName runat="server" ID="SomeUniqueID" [optional parameters] />
So, in the case of your control, you've set TagPrefix="sp" and TagName="Spinner". So your control placement will look like this:
<sp:Spinner runat="server" ID="uxAlumniSpinner" />
(ID is an example)
From your control code, you don't have any parameters configured, so the above would work fine. But you could provide at least one parameter, and probably should in order to make the control more reusable.
For example, you've got a hard-coded value of 75 in your method call. I assume that's pointing to an Ektron Folder, Taxonomy, or Collection. Regardless, it's some container ID. You might want to use this control in multiple places with different sources for the data - different container IDs. The way you've set this up, you'll have to make a new control every time just to update that value.
So if we add a public property to your control, so that the code-behind looks like this:
using Ektron.Custom.SmartForms;
using System;
using System.Linq;
public partial class Source_Controls_Alumni_Gallery : System.Web.UI.UserControl
{
// Added Property
private long _containerId = 0;
public long ContainerID {
get { return _containerId; }
set { _containerId = value; }
}
/////////
protected void Page_Load(object sender, EventArgs e)
{
// Added inverted conditional to escape method
// if the _containerId is invalid.
if(_containerId <= 0) return;
///////////
var pressPhotoManager = new PressPhotoManager();
// Whichever folder Id...
var photos = pressPhotoManager.GetList(_containerId);
if (photos != null && photos.Any())
{
uxPhotoGallery.DataSource = photos;
uxPhotoGallery.DataBind();
}
}
}
Then you could specify the container ID whenever and wherever you place the control. Like so:
<sp:Spinner runat="server" ID="uxAlumniSpinner" ContainerID="75" />
Making your final in-template markup:
<%# Register Src="~/Source/Controls/JoinUs/StaffAndParalegals/SPContactDetails.ascx" TagPrefix="uc1" TagName="SPContactDetails" %>
<%# Register Src="~/Source/Controls/Shared/TextImageAssetBlockModules.ascx" TagPrefix="uc1" TagName="TextImageAssetBlockModules" %>
<%# Register Src="~/Source/Controls/Shared/TextLinkBlockControl.ascx" TagPrefix="uc1" TagName="TextLinkBlockControl" %>
<%# Register TagPrefix="sp" TagName="Spinner" Src="~/Source/Controls/Alumni/Gallery.ascx" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<uc1:SubHeader runat="server" ID="SubHeader" />
<div class="container non-responsive">
<div class="row">
<div class="col-sm-8 alpha">
<uc1:PrimarySection runat="server" ID="PrimarySection" />
<div class="primary">
<div class="container non-responsive">
<div class="row">
<div class="col-sm-8 alpha">
<div class="primary">
<sp:Spinner runat="server" ID="uxAlumniSpinner" ContainerID="75" />
</div>
</div>
<div class="col-sm-4 beta">
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-4 beta">
<uc1:SPContactDetails runat="server" ID="SPContactDetails" />
<uc1:SPFilters runat="server" ID="SPFilters" Heading="Staff and Paralegal Openings" Text="Select an office below to learn more about current opportunities" />
<uc1:RelatedContentModules runat="server" ID="RelatedContentModules" />
<uc1:TextLinkBlockControl runat="server" ID="TextLinkBlockControl" />
<uc1:TextImageAssetBlockModules runat="server" ID="TextImageAssetBlockModules" />
</div>
</div>
</div>
</asp:Content>
I have a user control which is used to display search results. The HTML for each result displayed will vary based on the type of result being displayed: "contacts" are displayed in one way, "news articles" are displayed in another, etc. There are around 10 different types of results that are all marked up differently when they get to HTML — so I need around 10 or so different templates for individual results that I can choose between based on the current item being displayed.
I'm using an asp:Repeater to display the results, but I don't know how to select the appropriate template within the asp:Repeater <ItemTemplate>. Ideally I'd like the ASP to select the appropriate template to use based upon the object type being passed in via the searchResultsRepeater.DataSource — but unfortunately I can't use switch on type (see this blog entry for C# switch on type). I can however just pass through an enum value for the type of result being displayed.
In the backend C# code I have an abstract inline SearchResult class, and children of that class like ContactSearchResult, NewsArticleSearchResult, etc. The searchResultsRepeater.DataSource would then be bound to a List<SearchResult>. Each SearchResult contains a ResultListingType type field which gives the type of the listing to be displayed.
Attempt 1: using control flow inside the ASP itself
My first attempt was something like this:
<asp:Repeater ID="searchResultsRepeater" runat="server">
<ItemTemplate>
<div class="item">
<% switch (DataBinder.Eval(Container.DataItem, "type")) { %>
<% case ResultListingType.CONTACT: %>
<p><%# DataBinder.Eval(Container.DataItem, "firstName") %></p>
<p><%# DataBinder.Eval(Container.DataItem, "lastName") %></p>
<% break; %>
<% case ResultListingType.NEWS: %>
<p><%# DataBinder.Eval(Container.DataItem, "newsHeadline") %></p>
<p><%# DataBinder.Eval(Container.DataItem, "newsDate") %></p>
<% break; %>
<% Case AnotherTypeOfListing1: %>
<% Case AnotherTypeOfListing2: %>
<% Case AnotherTypeOfListing3: %>
<% Case AnotherTypeOfListing4: %>
<% Case AnotherTypeOfListing5: %>
<% etc... %>
<% } %>
</div>
</ItemTemplate>
</asp:Repeater>
Unfortunately, this doesn't work:
"switch" and "if" both give "invalid expression term" inside the <%# ... %> brackets.
"Container.DataItem" gives "the name "Container" does not exist in the current context" inside <% ... %> brackets.
Attempt 2: setting asp:PlaceHolder's to Visible = False
I found something that looked useful at how to change the ItemTemplate used in an asp:repeater?. I then tried something like:
<asp:Repeater ID="searchResultsRepeater" runat="server">
<ItemTemplate>
<div class="item">
<asp:PlaceHolder ID="newsResultListing" runat="server">
<p><%# DataBinder.Eval(Container.DataItem, "newsHeadline") %></p>
<p><%# DataBinder.Eval(Container.DataItem, "newsDate") %></p>
</asp:PlaceHolder>
<asp:PlaceHolder ID="contactResultListing" runat="server">
<p><%# DataBinder.Eval(Container.DataItem, "firstName") %></p>
<p><%# DataBinder.Eval(Container.DataItem, "lastName") %></p>
</asp:PlaceHolder>
</div>
</ItemTemplate>
</asp:Repeater>
In my ItemDataBound event I did:
Control newsResultListing = e.Item.FindControl("newsResultListing");
newsResultListing.Visible = false;
Control contactResultListing = e.Item.FindControl("contactResultListing");
contactResultListing.Visible = false;
switch (item.type)
{
case ResultListingType.CONTACT:
contactResultListing.Visible = true;
break;
case ResultListingType.NEWS:
newsResultListing.Visible = true;
break;
default:
throw new Exception("Unknown result listing type");
}
Unfortunately this doesn't work because ASP seems to still be running the contents of the PlaceHolder even after I set Visible = false. I get the error "DataBinding: 'usercontrols_ResultsListing+ContactResultsListing' does not contain a property with the name 'newsHeadline'" — i.e. the newsResultListing PlaceHolder is still looking for the "newsHeadline" field, even though that field doesn't exist for the result listing type being displayed.
In fact I've tried a quick test throw new Exception("e"); in my ItemDataBound, and it looks like the "DataBinding" error is thrown even before control flow gets to the ItemDataBound method, so there's really nothing I can do in there to avoid this error.
I suppose I could add every single field to the parent class and leave most of them null in my children, but that seems really ugly.
Is there a way to make this work, or an easier way to vary my ItemTemplate based upon the type of Container.DataItem I'm currently iterating over? I'm very new to ASP so there's likely something simple that I've missed. :)
OK, I think I've found a solution — I've created multiple additional user controls, one for each type of search result. Each one of these controls defines the HTML template for its corresponding type of search result.
My asp:Repeater contains absolutely nothing inside its ItemTemplate:
<asp:Repeater ID="searchResultsRepeater" runat="server">
<ItemTemplate>
<%-- empty template: we insert usercontrols in the ItemDataBound --%>
</ItemTemplate>
</asp:Repeater>
I bind a List<SearchResultData> to my asp:Repeater as before, and as before this list contains more specific subtypes of SearchResultData based on the type of result to be shown.
In my ItemDataBound handler I instantiate one of those user controls based on the type of data in e.Item.DataItem and then insert that user control into the repeater:
var aspxItem = e.Item;
var dataItem = (SearchResultData) e.Item.DataItem;
if (dataItem is ContactSearchResult.ContactSearchResultData)
{
var contactSearchResultUC = LoadControl("~/UserControls/ResultsListingSearchResult/ContactSearchResult.ascx") as ASP.ContactSearchResult;
contactSearchResultUC.data = (ContactSearchResult.ContactSearchResultData)dataItem;
aspxItem.Controls.Add(contactSearchResultUC);
}
else if (dataItem is NewsArticleSearchResult.NewsArticleSearchResultData)
{
var newsArticleSearchResultUC = LoadControl("~/UserControls/ResultsListingSearchResult/NewsArticleSearchResult.ascx") as ASP.NewsArticleSearchResult;
newsArticleSearchResultUC.data = (NewsArticleSearchResult.NewsArticleSearchResultData)dataItem;
aspxItem.Controls.Add(newsArticleSearchResultUC);
}
...etc
To add to George's solution, the <ItemTemplate> can be a mix of markup and dynamic controls. The following example renders a table of name/value pairs.
<table cellspacing="0" cellpadding="5" border="0" width="100%">
<tbody>
<asp:Repeater ID="TheRepeater" OnItemDataBound="TheRepeater_ItemDataBound" runat="server">
<ItemTemplate>
<tr>
<td class="LabelText"><%# ((NameValuePair)Container.DataItem).Name%>:</td>
<td class="ValueText">
<asp:PlaceHolder ID="ValuePlaceHolder" runat="server" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</tbody>
</table>
Code-behind
protected void TheRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (ListItemType.Item == e.Item.ItemType || ListItemType.AlternatingItem == e.Item.ItemType)
{
NameValuePair nvp = (NameValuePair)e.Item.DataItem;
PlaceHolder container = (PlaceHolder)e.Item.FindControl("ValuePlaceHolder");
if (typeof(nvp.Value) is String)
{
Literal textControl = new Literal() { Mode = LiteralMode.Encode, Text = (string)nvp.Value, EnableViewState = false };
container.Controls.Add(textControl);
}
...
You will need to override the ItemDataBound event handler and control it there.
Alternatively, put the logic into a user control and put the user control into the template instead.
The user control will still need to implement the appropraite switching, but makes it easier to reuse the logic.
For some reason, I cannot get text into any textbox or label!
I'm using Master pages and the code is going in the code behind view. I have created the textbox:
<asp:Textbox ID="whatever" runat="Server">
When I want to add some text I simply add the code in the code behind view like:
whatever.Text = "myText";
I get an error that says:
"System.NullReferenceException:Object reference not set to an instance of an object"
hightlighting this line in red: whatever.Text = "myText";
I guess its because it saying it not there but how can it let me reference the textbox?
Apologies if the answer is on the site, I have searched but found nothing. :)
This is my code in Basket.asp - I've changed the textbox to a label, it's called bskItems
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder3" runat="server">
<asp:Label ID="bskItems" runat="server"></asp:Label>
<div id="cart">
<asp:Button ID="btnCheckout" CssClass="BasketBtnAdd" runat="server" CommandName="checkout" Text="Checkout" />
</div>
</asp:Content>
This is my masterpage, where I'm using a loginView. ContentPlaceHolder3 is where the textbox should be. I only want it to display a count of items.
<asp:LoginView ID="loginView" runat="server">
<LoggedInTemplate>
<asp:LoginName ID="loginName" runat="server" FormatString="Hi, {0}!"/>
(<asp:LoginStatus ID="loginStatus" runat="server" />)
<%
if (HttpContext.Current.User.IsInRole("Admin"))
{
%>
<asp:SiteMapDataSource ID="admin" SiteMapProvider="admin" runat="server" ShowStartingNode="false" />
<asp:Menu ID="Menu" runat="server" DataSourceID="admin">
<StaticItemTemplate>
<%# Eval("Text") %>
</StaticItemTemplate>
</asp:Menu>
<%
}
if (HttpContext.Current.User.IsInRole("Users"))
{
%>
<asp:SiteMapDataSource ID="user" runat="server" SiteMapProvider="user" ShowStartingNode="false" />
<asp:Menu ID="Menu1" runat="server" DataSourceID="user">
<StaticItemTemplate>
<%# Eval("Text") %>
</StaticItemTemplate>
</asp:Menu>
<%
}
%>
<asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server"></asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="ContentPlaceHolder3" runat="server"></asp:ContentPlaceHolder>
</LoggedInTemplate>
<AnonymousTemplate>
<asp:LoginStatus ID="loginStatus" runat="server" />
<asp:SiteMapDataSource ID="anon" runat="server" SiteMapProvider="anon" ShowStartingNode="false" />
<asp:Menu ID="Menu2" runat="server" DataSourceID="anon">
<StaticItemTemplate>
<%# Eval("Text") %>
</StaticItemTemplate>
</asp:Menu>
</AnonymousTemplate>
</asp:LoginView>
In addition to the other answers, if you're setting the value in Page.OnLoad, remember that the Master page controls haven't been created yet.
Here's a complete layout of the order in which things happen: Complete Lifecycle of an ASP Page
What I usualy do is to make the control visible as a property of my MasterPage.
On the master page (AMasterPage.master):
public TextBox MyTextBox { get { return this.theTextBoxControl; } }
So then, on a child using this masterPage (APage.aspx) :
((AMasterPage)this.Master).MyTextBox.Text = "myText";
When accessing Master Page members from Code-Behind in a Content Place Holder file, I believe you need to do:
this.Master.whatever.Text = "new Text";
Check this link on ASP.NET Master Pages, from MSDN.
You need to do get a reference to the textbox on the master page, then set the text
TextBox tb = Master.Page.FindControl("whatever") as TextBox;
if(tb != null)
{
tb.Text = "myText";
}
Set the ClientIDMode on the textbox to "Static". When the page is rendered it assigns the TextBox's ID to something random. By changing the ClientIDMode to "Static", you should be able to reference the ID because the ID will stay the same and not change.
Or try adding an OnDataBinding event handler and casting the "sender" as a (TextBox). For example:
protected void TextBox_OnDataBinding(object sender, EventArgs e)
{
var txt = (TextBox)sender;
txt.Text = "Something";
}
This should talk to the control directly.
I'm trying to display an image inside a ListView control based on the value of a databound property. I've tried two methods of doing this (one at a time) and both returned errors of "The server tag is not well formed". Consider the code below.
<ItemTemplate>
<div class="left">
<!-- Method 1 -->
<img src="media-play-button.png" alt="Play" class="mediaplay noborder" runat="server" visible="<%# Eval("MediaType").ToString() == "video" %>" />
<!-- Method 2 -->
<%# if (((MediaLink)Container.DataItem).MediaType == "video") { %>
<img src="media-play-button.png" alt="Play" class="mediaplay noborder" />
<%# } %>
</div>
</ItemTemplate>
Method 1:
Instead of using " for the visible attribute value, use ':
<img src="media-play-button.png" alt="Play" class="mediaplay noborder"
runat="server" visible='<%# Eval("MediaType").ToString() == "video" %>' />
Using " causes the string to terminate after <%# Eval(.
Method 2:
Don't use binding expressions (<%#%>) for coding blocks (<%%>):
<% if (((MediaLink)Container.DataItem).MediaType == "video") { %>
<img src="media-play-button.png" alt="Play" class="mediaplay noborder" />
<% } %>
I was working on an ASP.NET MVC template today, and after staring at all those fluorescent yellow % tags for long enough, I basically decided I had had enough, so I painstakingly modified my ascx file to look like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% if (Model == null)
{ %>
<%= ViewData.ModelMetadata.NullDisplayText %>
<% }
else if (ViewData.TemplateInfo.TemplateDepth > 1)
{ %>
<%= ViewData.ModelMetadata.SimpleDisplayText %>
<% }
else
{ %>
<% foreach (var prop in ViewData.ModelMetadata.Properties.Where(
pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
{ %>
<% if (prop.HideSurroundingHtml)
{ %>
<%= Html.Display(prop.PropertyName) %>
<% }
else
{ %>
<% if (!String.IsNullOrEmpty(prop.GetDisplayName()))
{ %>
<span class="display-label">
<%= prop.GetDisplayName() %>
</span>
<% } %>
<span class="display-field">
<%= Html.Display(prop.PropertyName) %>
</span>
<% } %>
<% } %>
<% } %>
Ahh readability at last. The only problem is, it takes way to long to do this by hand. I need a way to automate this. Some kind of code formatting solution. Perhaps a macro or a Visual Studio add-in or ...? What do you advise?
Update
I'm now planning to refactor out most of the logic from my markup (see Mike's answer below), but in the mean time, I came up with a more manageable way to format ascx files that have a mixture of code and html. The code is a little more spread out this way, but it's much easier to format the code like this in the first place, and it's much easier to work with as well.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%
if (Model == null)
{
%>
<%= ViewData.ModelMetadata.NullDisplayText %>
<%
}
else if (ViewData.TemplateInfo.TemplateDepth > 1)
{
%>
<%= ViewData.ModelMetadata.SimpleDisplayText %>
<%
}
else
{
%>
<%
foreach (var prop in ViewData.ModelMetadata.Properties.Where(
pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
{
if (prop.HideSurroundingHtml)
{
%>
<%= Html.Display(prop.PropertyName) %>
<%
}
else
{
%>
<div class="display-row">
<%
if (!String.IsNullOrEmpty(prop.GetDisplayName()))
{
%>
<div class="display-label">
<%= prop.GetDisplayName() %>
</div>
<%
}
%>
<div class="display-field">
<%= Html.Display(prop.PropertyName) %>
</div>
</div>
<%
}
}
}
%>
I believe your "tag soup" pain is actually a symptom of a different problem: you're feeling it because you've got logic in your view. Views should be very lightweight, with little or no logic. Your logic should be in your controllers, which can decide to render different views depending on the logic. Or you can put the logic into helpers.
See this article by Rob Conery
With proper view model (and optionally, with spark view engine), there is no tag soup.
Particularly, if templates are used.
Can't tell much about this example (even less - to sort it out), but for me - usually it's all about sense of tidiness and ability to structure things properly.
"I'm looking for a code formatting solution." => then you must check out spark. It 'htmlifies' your views even if they do contain logic.
Your example in it (without restructuring anything) =>
<var nullText="ViewData.ModelMetadata.NullDisplayText"
templateDepth="ViewData.TemplateInfo.TemplateDepth"
simpleDisplayText="ViewData.ModelMetadata.SimpleDisplayText"
props="ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm))"
m="ViewData.Model"/>
<if condition="m==null">
${nullText}
</if>
<elseif condition="templateDepth>1">
${simpleDisplayText}
</elseif>
<else>
<for each="var prop in props">
<if condition="prop.HideSurroundingHtml">
${Html.Display(prop.PropertyName)}
</if>
<else>
<span if="!string.IsNullOrEmpty(prop.GetDisplayName()" class="display-field">
${prop.GetDisplayName()}
</span>
<span class="display-field">
${Html.Display(prop.ProperyName)}
</span>
</else>
</for>
</else>
Might be wrong somewhere, but you got the idea.
For our current project, we cleaned up all the if-elses somewhat by writing an HTML helper:
public static void WriteIf(this HtmlHelper helper, bool condition, string truePart, string falsePart)
{
helper.ViewContext.HttpContext.Response.Write(condition ? truePart : falsePart);
}
and then in the HTML, you would say:
<% Html.WriteIf(Model.IsTrue(), "TrueText", "FalseText"); %>